mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
TE6 打飞机Demo
TE6 打飞机Demo
This commit is contained in:
183
UnityProject/Packages/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
183
UnityProject/Packages/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public partial struct UniTask
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(IEnumerable<UniTask<T>> tasks)
|
||||
{
|
||||
return new WhenEachEnumerable<T>(tasks);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(params UniTask<T>[] tasks)
|
||||
{
|
||||
return new WhenEachEnumerable<T>(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct WhenEachResult<T>
|
||||
{
|
||||
public T Result { get; }
|
||||
public Exception Exception { get; }
|
||||
|
||||
//[MemberNotNullWhen(false, nameof(Exception))]
|
||||
public bool IsCompletedSuccessfully => Exception == null;
|
||||
|
||||
//[MemberNotNullWhen(true, nameof(Exception))]
|
||||
public bool IsFaulted => Exception != null;
|
||||
|
||||
public WhenEachResult(T result)
|
||||
{
|
||||
this.Result = result;
|
||||
this.Exception = null;
|
||||
}
|
||||
|
||||
public WhenEachResult(Exception exception)
|
||||
{
|
||||
if (exception == null) throw new ArgumentNullException(nameof(exception));
|
||||
this.Result = default;
|
||||
this.Exception = exception;
|
||||
}
|
||||
|
||||
public void TryThrow()
|
||||
{
|
||||
if (IsFaulted)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(Exception).Throw();
|
||||
}
|
||||
}
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
if (IsFaulted)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(Exception).Throw();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IsCompletedSuccessfully)
|
||||
{
|
||||
return Result?.ToString() ?? "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"Exception{{{Exception.Message}}}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum WhenEachState : byte
|
||||
{
|
||||
NotRunning,
|
||||
Running,
|
||||
Completed
|
||||
}
|
||||
|
||||
internal sealed class WhenEachEnumerable<T> : IUniTaskAsyncEnumerable<WhenEachResult<T>>
|
||||
{
|
||||
IEnumerable<UniTask<T>> source;
|
||||
|
||||
public WhenEachEnumerable(IEnumerable<UniTask<T>> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<WhenEachResult<T>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : IUniTaskAsyncEnumerator<WhenEachResult<T>>
|
||||
{
|
||||
readonly IEnumerable<UniTask<T>> source;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
Channel<WhenEachResult<T>> channel;
|
||||
IUniTaskAsyncEnumerator<WhenEachResult<T>> channelEnumerator;
|
||||
int completeCount;
|
||||
WhenEachState state;
|
||||
|
||||
public Enumerator(IEnumerable<UniTask<T>> source, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public WhenEachResult<T> Current => channelEnumerator.Current;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (state == WhenEachState.NotRunning)
|
||||
{
|
||||
state = WhenEachState.Running;
|
||||
channel = Channel.CreateSingleConsumerUnbounded<WhenEachResult<T>>();
|
||||
channelEnumerator = channel.Reader.ReadAllAsync().GetAsyncEnumerator(cancellationToken);
|
||||
|
||||
if (source is UniTask<T>[] array)
|
||||
{
|
||||
ConsumeAll(this, array, array.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var rentArray = ArrayPoolUtil.Materialize(source))
|
||||
{
|
||||
ConsumeAll(this, rentArray.Array, rentArray.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return channelEnumerator.MoveNextAsync();
|
||||
}
|
||||
|
||||
static void ConsumeAll(Enumerator self, UniTask<T>[] array, int length)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
RunWhenEachTask(self, array[i], length).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
static async UniTaskVoid RunWhenEachTask(Enumerator self, UniTask<T> task, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await task;
|
||||
self.channel.Writer.TryWrite(new WhenEachResult<T>(result));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.channel.Writer.TryWrite(new WhenEachResult<T>(ex));
|
||||
}
|
||||
|
||||
if (Interlocked.Increment(ref self.completeCount) == length)
|
||||
{
|
||||
self.state = WhenEachState.Completed;
|
||||
self.channel.Writer.TryComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (channelEnumerator != null)
|
||||
{
|
||||
await channelEnumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
if (state != WhenEachState.Completed)
|
||||
{
|
||||
state = WhenEachState.Completed;
|
||||
channel.Writer.TryComplete(new OperationCanceledException());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user