Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 1 addition & 237 deletions src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenAll.cs
Original file line number Diff line number Diff line change
@@ -1,237 +1 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;

namespace Cysharp.Threading.Tasks
{
public partial struct UniTask
{
public static UniTask<T[]> WhenAll<T>(params UniTask<T>[] tasks)
{
if (tasks.Length == 0)
{
return UniTask.FromResult(Array.Empty<T>());
}

return new UniTask<T[]>(new WhenAllPromise<T>(tasks, tasks.Length), 0);
}

public static UniTask<T[]> WhenAll<T>(IEnumerable<UniTask<T>> tasks)
{
using (var span = ArrayPoolUtil.Materialize(tasks))
{
var promise = new WhenAllPromise<T>(span.Array, span.Length); // consumed array in constructor.
return new UniTask<T[]>(promise, 0);
}
}

public static UniTask WhenAll(params UniTask[] tasks)
{
if (tasks.Length == 0)
{
return UniTask.CompletedTask;
}

return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0);
}

public static UniTask WhenAll(IEnumerable<UniTask> tasks)
{
using (var span = ArrayPoolUtil.Materialize(tasks))
{
var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor.
return new UniTask(promise, 0);
}
}

sealed class WhenAllPromise<T> : IUniTaskSource<T[]>
{
T[] result;
int completeCount;
UniTaskCompletionSourceCore<T[]> core; // don't reset(called after GetResult, will invoke TrySetException.)

public WhenAllPromise(UniTask<T>[] tasks, int tasksLength)
{
TaskTracker.TrackActiveTask(this, 3);

this.completeCount = 0;

if (tasksLength == 0)
{
this.result = Array.Empty<T>();
core.TrySetResult(result);
return;
}

this.result = new T[tasksLength];

for (int i = 0; i < tasksLength; i++)
{
UniTask<T>.Awaiter awaiter;
try
{
awaiter = tasks[i].GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
continue;
}

if (awaiter.IsCompleted)
{
TryInvokeContinuation(this, awaiter, i);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAllPromise<T>, UniTask<T>.Awaiter, int>)state)
{
TryInvokeContinuation(t.Item1, t.Item2, t.Item3);
}
}, StateTuple.Create(this, awaiter, i));
}
}
}

static void TryInvokeContinuation(WhenAllPromise<T> self, in UniTask<T>.Awaiter awaiter, int i)
{
try
{
self.result[i] = awaiter.GetResult();
}
catch (Exception ex)
{
self.core.TrySetException(ex);
return;
}

if (Interlocked.Increment(ref self.completeCount) == self.result.Length)
{
self.core.TrySetResult(self.result);
}
}

public T[] GetResult(short token)
{
TaskTracker.RemoveTracking(this);
GC.SuppressFinalize(this);
return core.GetResult(token);
}

void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}

public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}

public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}

public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
}

sealed class WhenAllPromise : IUniTaskSource
{
int completeCount;
int tasksLength;
UniTaskCompletionSourceCore<AsyncUnit> core; // don't reset(called after GetResult, will invoke TrySetException.)

public WhenAllPromise(UniTask[] tasks, int tasksLength)
{
TaskTracker.TrackActiveTask(this, 3);

this.tasksLength = tasksLength;
this.completeCount = 0;

if (tasksLength == 0)
{
core.TrySetResult(AsyncUnit.Default);
return;
}

for (int i = 0; i < tasksLength; i++)
{
UniTask.Awaiter awaiter;
try
{
awaiter = tasks[i].GetAwaiter();
}
catch (Exception ex)
{
core.TrySetException(ex);
continue;
}

if (awaiter.IsCompleted)
{
TryInvokeContinuation(this, awaiter);
}
else
{
awaiter.SourceOnCompleted(state =>
{
using (var t = (StateTuple<WhenAllPromise, UniTask.Awaiter>)state)
{
TryInvokeContinuation(t.Item1, t.Item2);
}
}, StateTuple.Create(this, awaiter));
}
}
}

static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
}
catch (Exception ex)
{
self.core.TrySetException(ex);
return;
}

if (Interlocked.Increment(ref self.completeCount) == self.tasksLength)
{
self.core.TrySetResult(AsyncUnit.Default);
}
}

public void GetResult(short token)
{
TaskTracker.RemoveTracking(this);
GC.SuppressFinalize(this);
core.GetResult(token);
}

public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}

public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}

public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
}
}
}
\ufeff#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Cysharp.Threading.Tasks.Internal;\n\nnamespace Cysharp.Threading.Tasks\n{\n public partial struct UniTask\n {\n /// <summary>\n /// Runs all tasks in parallel. If any task throws an exception, the returned task\n /// completes immediately with that exception \u2014 remaining tasks continue running but\n /// their results are discarded.\n /// </summary>\n /// <remarks>\n /// NOTE: This differs from standard .NET Task.WhenAll, which waits for ALL tasks to\n /// complete before throwing AggregateException. If you need \"wait for all then collect\n /// errors\", consider wrapping each task with try-catch or using SuppressCancellationThrow\n /// on individual tasks before calling WhenAll.\n /// </remarks>\n public static UniTask<T[]> WhenAll<T>(params UniTask<T>[] tasks)\n {\n if (tasks.Length == 0)\n {\n return UniTask.FromResult(Array.Empty<T>());\n }\n\n return new UniTask<T[]>(new WhenAllPromise<T>(tasks, tasks.Length), 0);\n }\n\n public static UniTask<T[]> WhenAll<T>(IEnumerable<UniTask<T>> tasks)\n {\n using (var span = ArrayPoolUtil.Materialize(tasks))\n {\n var promise = new WhenAllPromise<T>(span.Array, span.Length); // consumed array in constructor.\n return new UniTask<T[]>(promise, 0);\n }\n }\n\n /// <summary>\n /// Runs all tasks in parallel. If any task throws, the returned task completes\n /// immediately \u2014 see <see cref=\"WhenAll{T}(UniTask{T}[])\"/> for behavioral notes.\n /// </summary>\n public static UniTask WhenAll(params UniTask[] tasks)\n {\n if (tasks.Length == 0)\n {\n return UniTask.CompletedTask;\n }\n\n return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0);\n }\n\n public static UniTask WhenAll(IEnumerable<UniTask> tasks)\n {\n using (var span = ArrayPoolUtil.Materialize(tasks))\n {\n var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor.\n return new UniTask(promise, 0);\n }\n }\n\n sealed class WhenAllPromise<T> : IUniTaskSource<T[]>\n {\n T[] result;\n int completeCount;\n UniTaskCompletionSourceCore<T[]> core; // don't reset(called after GetResult, will invoke TrySetException.)\n\n public WhenAllPromise(UniTask<T>[] tasks, int tasksLength)\n {\n TaskTracker.TrackActiveTask(this, 3);\n\n this.completeCount = 0;\n\n if (tasksLength == 0)\n {\n this.result = Array.Empty<T>();\n core.TrySetResult(result);\n return;\n }\n\n this.result = new T[tasksLength];\n\n for (int i = 0; i < tasksLength; i++)\n {\n UniTask<T>.Awaiter awaiter;\n try\n {\n awaiter = tasks[i].GetAwaiter();\n }\n catch (Exception ex)\n {\n core.TrySetException(ex);\n continue;\n }\n\n if (awaiter.IsCompleted)\n {\n TryInvokeContinuation(this, awaiter, i);\n }\n else\n {\n awaiter.SourceOnCompleted(state =>\n {\n using (var t = (StateTuple<WhenAllPromise<T>, UniTask<T>.Awaiter, int>)state)\n {\n TryInvokeContinuation(t.Item1, t.Item2, t.Item3);\n }\n }, StateTuple.Create(this, awaiter, i));\n }\n }\n }\n\n static void TryInvokeContinuation(WhenAllPromise<T> self, in UniTask<T>.Awaiter awaiter, int i)\n {\n try\n {\n self.result[i] = awaiter.GetResult();\n }\n catch (Exception ex)\n {\n self.core.TrySetException(ex);\n return;\n }\n\n if (Interlocked.Increment(ref self.completeCount) == self.result.Length)\n {\n self.core.TrySetResult(self.result);\n }\n }\n\n public T[] GetResult(short token)\n {\n TaskTracker.RemoveTracking(this);\n GC.SuppressFinalize(this);\n return core.GetResult(token);\n }\n\n void IUniTaskSource.GetResult(short token)\n {\n GetResult(token);\n }\n\n public UniTaskStatus GetStatus(short token)\n {\n return core.GetStatus(token);\n }\n\n public UniTaskStatus UnsafeGetStatus()\n {\n return core.UnsafeGetStatus();\n }\n\n public void OnCompleted(Action<object> continuation, object state, short token)\n {\n core.OnCompleted(continuation, state, token);\n }\n }\n\n sealed class WhenAllPromise : IUniTaskSource\n {\n int completeCount;\n int tasksLength;\n UniTaskCompletionSourceCore<AsyncUnit> core; // don't reset(called after GetResult, will invoke TrySetException.)\n\n public WhenAllPromise(UniTask[] tasks, int tasksLength)\n {\n TaskTracker.TrackActiveTask(this, 3);\n\n this.tasksLength = tasksLength;\n this.completeCount = 0;\n\n if (tasksLength == 0)\n {\n core.TrySetResult(AsyncUnit.Default);\n return;\n }\n\n for (int i = 0; i < tasksLength; i++)\n {\n UniTask.Awaiter awaiter;\n try\n {\n awaiter = tasks[i].GetAwaiter();\n }\n catch (Exception ex)\n {\n core.TrySetException(ex);\n continue;\n }\n\n if (awaiter.IsCompleted)\n {\n TryInvokeContinuation(this, awaiter);\n }\n else\n {\n awaiter.SourceOnCompleted(state =>\n {\n using (var t = (StateTuple<WhenAllPromise, UniTask.Awaiter>)state)\n {\n TryInvokeContinuation(t.Item1, t.Item2);\n }\n }, StateTuple.Create(this, awaiter));\n }\n }\n }\n\n static void TryInvokeContinuation(WhenAllPromise self, in UniTask.Awaiter awaiter)\n {\n try\n {\n awaiter.GetResult();\n }\n catch (Exception ex)\n {\n self.core.TrySetException(ex);\n return;\n }\n\n if (Interlocked.Increment(ref self.completeCount) == self.tasksLength)\n {\n self.core.TrySetResult(AsyncUnit.Default);\n }\n }\n\n public void GetResult(short token)\n {\n TaskTracker.RemoveTracking(this);\n GC.SuppressFinalize(this);\n core.GetResult(token);\n }\n\n public UniTaskStatus GetStatus(short token)\n {\n return core.GetStatus(token);\n }\n\n public UniTaskStatus UnsafeGetStatus()\n {\n return core.UnsafeGetStatus();\n }\n\n public void OnCompleted(Action<object> continuation, object state, short token)\n {\n core.OnCompleted(continuation, state, token);\n }\n }\n }\n}\n"