UniTask/Assets/UniRx.Async/UniTask.WhenAny.cs

369 lines
12 KiB
C#
Raw Normal View History

2019-05-19 23:14:47 +08:00
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
2020-04-21 12:36:23 +08:00
using System.Collections.Generic;
2019-05-19 23:14:47 +08:00
using System.Threading;
2020-04-21 12:36:23 +08:00
using UniRx.Async.Internal;
2019-05-19 23:14:47 +08:00
namespace UniRx.Async
{
public partial struct UniTask
{
2020-04-21 12:36:23 +08:00
public static UniTask<(bool hasResultLeft, T result)> WhenAny<T>(UniTask<T> leftTask, UniTask rightTask)
{
return new UniTask<(bool, T)>(new WhenAnyLRPromise<T>(leftTask, rightTask), 0);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public static UniTask<(int winArgumentIndex, T result)> WhenAny<T>(params UniTask<T>[] tasks)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return new UniTask<(int, T)>(new WhenAnyPromise<T>(tasks, tasks.Length), 0);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public static UniTask<(int winArgumentIndex, T result)> WhenAny<T>(IEnumerable<UniTask<T>> tasks)
2019-05-19 23:14:47 +08:00
{
using (var span = ArrayPoolUtil.CopyToRentArray(tasks))
2020-04-21 12:36:23 +08:00
{
return new UniTask<(int, T)>(new WhenAnyPromise<T>(span.Array, span.Length), 0);
}
2019-05-19 23:14:47 +08:00
}
/// <summary>Return value is winArgumentIndex</summary>
2020-04-21 12:36:23 +08:00
public static UniTask<int> WhenAny(params UniTask[] tasks)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return new UniTask<int>(new WhenAnyPromise(tasks, tasks.Length), 0);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
/// <summary>Return value is winArgumentIndex</summary>
public static UniTask<int> WhenAny(IEnumerable<UniTask> tasks)
2019-05-19 23:14:47 +08:00
{
using (var span = ArrayPoolUtil.CopyToRentArray(tasks))
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return new UniTask<int>(new WhenAnyPromise(span.Array, span.Length), 0);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
sealed class WhenAnyLRPromise<T> : IUniTaskSource<(bool, T)>
{
int completedCount;
int winArgumentIndex;
UniTaskCompletionSourceCore<(bool, T)> core;
public WhenAnyLRPromise(UniTask<T> leftTask, UniTask rightTask)
2019-05-19 23:14:47 +08:00
{
TaskTracker.TrackActiveTask(this, 3);
2020-04-21 12:36:23 +08:00
{
UniTask<T>.Awaiter awaiter;
try
{
awaiter = leftTask.GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
goto RIGHT;
}
if (awaiter.IsCompleted)
{
TryLeftInvokeContinuation(this, awaiter);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAnyLRPromise<T>, UniTask<T>.Awaiter>)state)
{
TryLeftInvokeContinuation(t.Item1, t.Item2);
}
}, StateTuple.Create(this, awaiter));
}
}
RIGHT:
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
UniTask.Awaiter awaiter;
try
{
awaiter = rightTask.GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
return;
}
if (awaiter.IsCompleted)
{
TryRightInvokeContinuation(this, awaiter);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAnyLRPromise<T>, UniTask.Awaiter>)state)
{
TryRightInvokeContinuation(t.Item1, t.Item2);
}
}, StateTuple.Create(this, awaiter));
}
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
static void TryLeftInvokeContinuation(WhenAnyLRPromise<T> self, in UniTask<T>.Awaiter awaiter)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
T result;
2019-05-19 23:14:47 +08:00
try
{
2020-04-21 12:36:23 +08:00
result = awaiter.GetResult();
2019-05-19 23:14:47 +08:00
}
catch (Exception ex)
{
2020-04-21 12:36:23 +08:00
self.core.TrySetException(ex);
2019-05-19 23:14:47 +08:00
return;
}
2020-04-21 12:36:23 +08:00
if (Interlocked.Increment(ref self.completedCount) == 1)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
self.core.TrySetResult((true, result));
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
static void TryRightInvokeContinuation(WhenAnyLRPromise<T> self, in UniTask.Awaiter awaiter)
2019-05-19 23:14:47 +08:00
{
try
{
2020-04-21 12:36:23 +08:00
awaiter.GetResult();
2019-05-19 23:14:47 +08:00
}
catch (Exception ex)
{
2020-04-21 12:36:23 +08:00
self.core.TrySetException(ex);
2019-05-19 23:14:47 +08:00
return;
}
2020-04-21 12:36:23 +08:00
if (Interlocked.Increment(ref self.completedCount) == 1)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
self.core.TrySetResult((false, default));
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
public (bool, T) GetResult(short token)
2019-05-19 23:14:47 +08:00
{
TaskTracker.RemoveTracking(this);
2020-04-21 12:36:23 +08:00
GC.SuppressFinalize(this);
return core.GetResult(token);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public UniTaskStatus GetStatus(short token)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return core.GetStatus(token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
~WhenAnyLRPromise()
{
core.Reset();
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
sealed class WhenAnyPromise<T> : IUniTaskSource<(int, T)>
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
int completedCount;
2019-05-19 23:14:47 +08:00
int winArgumentIndex;
2020-04-21 12:36:23 +08:00
UniTaskCompletionSourceCore<(int, T)> core;
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public WhenAnyPromise(UniTask<T>[] tasks, int tasksLength)
2019-05-19 23:14:47 +08:00
{
TaskTracker.TrackActiveTask(this, 3);
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
for (int i = 0; i < tasksLength; i++)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
UniTask<T>.Awaiter awaiter;
try
{
awaiter = tasks[i].GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
continue; // consume others.
}
if (awaiter.IsCompleted)
{
TryInvokeContinuation(this, awaiter, i);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAnyPromise<T>, UniTask<T>.Awaiter, int>)state)
{
TryInvokeContinuation(t.Item1, t.Item2, t.Item3);
}
}, StateTuple.Create(this, awaiter, i));
}
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
static void TryInvokeContinuation(WhenAnyPromise<T> self, in UniTask<T>.Awaiter awaiter, int i)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
T result;
2019-05-19 23:14:47 +08:00
try
{
2020-04-21 12:36:23 +08:00
result = awaiter.GetResult();
2019-05-19 23:14:47 +08:00
}
catch (Exception ex)
{
2020-04-21 12:36:23 +08:00
self.core.TrySetException(ex);
2019-05-19 23:14:47 +08:00
return;
}
2020-04-21 12:36:23 +08:00
if (Interlocked.Increment(ref self.completedCount) == 1)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
self.core.TrySetResult((i, result));
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
public (int, T) GetResult(short token)
2019-05-19 23:14:47 +08:00
{
TaskTracker.RemoveTracking(this);
2020-04-21 12:36:23 +08:00
GC.SuppressFinalize(this);
return core.GetResult(token);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public UniTaskStatus GetStatus(short token)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return core.GetStatus(token);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public void OnCompleted(Action<object> continuation, object state, short token)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
core.OnCompleted(continuation, state, token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
~WhenAnyPromise()
{
core.Reset();
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
sealed class WhenAnyPromise : IUniTaskSource<int>
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
int completedCount;
2019-05-19 23:14:47 +08:00
int winArgumentIndex;
2020-04-21 12:36:23 +08:00
UniTaskCompletionSourceCore<int> core;
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public WhenAnyPromise(UniTask[] tasks, int tasksLength)
2019-05-19 23:14:47 +08:00
{
TaskTracker.TrackActiveTask(this, 3);
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
for (int i = 0; i < tasksLength; i++)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
UniTask.Awaiter awaiter;
try
{
awaiter = tasks[i].GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
continue; // consume others.
}
if (awaiter.IsCompleted)
{
TryInvokeContinuation(this, awaiter, i);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAnyPromise, UniTask.Awaiter, int>)state)
{
TryInvokeContinuation(t.Item1, t.Item2, t.Item3);
}
}, StateTuple.Create(this, awaiter, i));
}
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
static void TryInvokeContinuation(WhenAnyPromise self, in UniTask.Awaiter awaiter, int i)
2019-05-19 23:14:47 +08:00
{
try
{
2020-04-21 12:36:23 +08:00
awaiter.GetResult();
2019-05-19 23:14:47 +08:00
}
catch (Exception ex)
{
2020-04-21 12:36:23 +08:00
self.core.TrySetException(ex);
2019-05-19 23:14:47 +08:00
return;
}
2020-04-21 12:36:23 +08:00
if (Interlocked.Increment(ref self.completedCount) == 1)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
self.core.TrySetResult(i);
2019-05-19 23:14:47 +08:00
}
}
2020-04-21 12:36:23 +08:00
public int GetResult(short token)
2019-05-19 23:14:47 +08:00
{
TaskTracker.RemoveTracking(this);
2020-04-21 12:36:23 +08:00
GC.SuppressFinalize(this);
return core.GetResult(token);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public UniTaskStatus GetStatus(short token)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
return core.GetStatus(token);
2019-05-19 23:14:47 +08:00
}
2020-04-21 12:36:23 +08:00
public void OnCompleted(Action<object> continuation, object state, short token)
2019-05-19 23:14:47 +08:00
{
2020-04-21 12:36:23 +08:00
core.OnCompleted(continuation, state, token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
2019-05-19 23:14:47 +08:00
2020-04-21 12:36:23 +08:00
~WhenAnyPromise()
{
core.Reset();
2019-05-19 23:14:47 +08:00
}
}
}
}
#endif