mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-16 12:00:10 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5984b67ecb | ||
|
|
05fdf48058 | ||
|
|
647ed6ff82 | ||
|
|
0826b7e976 | ||
|
|
a51632cd4b | ||
|
|
bf945a7ef4 | ||
|
|
353f15e94f | ||
|
|
cf19f18662 | ||
|
|
fdb9d1cf95 | ||
|
|
2e0917428b | ||
|
|
0b16005f4b | ||
|
|
74bbe87b58 | ||
|
|
6f4131539b | ||
|
|
06283f0ffb | ||
|
|
dfe5ee43c2 |
19
README.md
19
README.md
@@ -160,7 +160,7 @@ UniTask provides three pattern of extension methods.
|
|||||||
|
|
||||||
> Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
> Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
||||||
|
|
||||||
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.
|
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`, `UniTask.WhenEach`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public async UniTaskVoid LoadManyAsync()
|
public async UniTaskVoid LoadManyAsync()
|
||||||
@@ -526,6 +526,9 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
|
|||||||
|
|
||||||
In UniTask, await directly uses native timing, while `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
|
In UniTask, await directly uses native timing, while `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
|
||||||
|
|
||||||
|
> Note: When using Unity 2023.1 or newer, ensure you have `using UnityEngine;` in the using statements of your file when working with new `UnityEngine.Awaitable` methods like `SceneManager.LoadSceneAsync`.
|
||||||
|
> This prevents compilation errors by avoiding the use of the `UnityEngine.AsyncOperation` version.
|
||||||
|
|
||||||
In the stacktrace, you can check where it is running in playerloop.
|
In the stacktrace, you can check where it is running in playerloop.
|
||||||
|
|
||||||

|

|
||||||
@@ -716,6 +719,19 @@ await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
|
|||||||
}, token);
|
}, token);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`UniTask.WhenEach` that is similar to .NET 9's `Task.WhenEach` can consume new way for await multiple tasks.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
await foreach (var result in UniTask.WhenEach(task1, task2, task3))
|
||||||
|
{
|
||||||
|
// The result is of type WhenEachResult<T>.
|
||||||
|
// It contains either `T Result` or `Exception Exception`.
|
||||||
|
// You can check `IsCompletedSuccessfully` or `IsFaulted` to determine whether to access `.Result` or `.Exception`.
|
||||||
|
// If you want to throw an exception when `IsFaulted` and retrieve the result when successful, use `GetResult()`.
|
||||||
|
Debug.Log(result.GetResult());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
UniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable<T>` or Rx in `IObservable<T>`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.
|
UniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable<T>` or Rx in `IObservable<T>`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@@ -1026,6 +1042,7 @@ Use UniTask type.
|
|||||||
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
||||||
| `Task.WhenAll` | `UniTask.WhenAll` |
|
| `Task.WhenAll` | `UniTask.WhenAll` |
|
||||||
| `Task.WhenAny` | `UniTask.WhenAny` |
|
| `Task.WhenAny` | `UniTask.WhenAny` |
|
||||||
|
| `Task.WhenEach` | `UniTask.WhenEach` |
|
||||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||||
| `Task.FromException` | `UniTask.FromException` |
|
| `Task.FromException` | `UniTask.FromException` |
|
||||||
| `Task.FromResult` | `UniTask.FromResult` |
|
| `Task.FromResult` | `UniTask.FromResult` |
|
||||||
|
|||||||
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal file
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace NetCoreTests
|
||||||
|
{
|
||||||
|
public class WhenEachTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Each()
|
||||||
|
{
|
||||||
|
var a = Delay(1, 3000);
|
||||||
|
var b = Delay(2, 1000);
|
||||||
|
var c = Delay(3, 2000);
|
||||||
|
|
||||||
|
var l = new List<int>();
|
||||||
|
await foreach (var item in UniTask.WhenEach(a, b, c))
|
||||||
|
{
|
||||||
|
l.Add(item.Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Should().Equal(2, 3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Error()
|
||||||
|
{
|
||||||
|
var a = Delay2(1, 3000);
|
||||||
|
var b = Delay2(2, 1000);
|
||||||
|
var c = Delay2(3, 2000);
|
||||||
|
|
||||||
|
var l = new List<WhenEachResult<int>>();
|
||||||
|
await foreach (var item in UniTask.WhenEach(a, b, c))
|
||||||
|
{
|
||||||
|
l.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
l[0].IsCompletedSuccessfully.Should().BeTrue();
|
||||||
|
l[0].IsFaulted.Should().BeFalse();
|
||||||
|
l[0].Result.Should().Be(2);
|
||||||
|
|
||||||
|
l[1].IsCompletedSuccessfully.Should().BeFalse();
|
||||||
|
l[1].IsFaulted.Should().BeTrue();
|
||||||
|
l[1].Exception.Message.Should().Be("ERROR");
|
||||||
|
|
||||||
|
l[2].IsCompletedSuccessfully.Should().BeTrue();
|
||||||
|
l[2].IsFaulted.Should().BeFalse();
|
||||||
|
l[2].Result.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTask<int> Delay(int id, int sleep)
|
||||||
|
{
|
||||||
|
await Task.Delay(sleep);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTask<int> Delay2(int id, int sleep)
|
||||||
|
{
|
||||||
|
await Task.Delay(sleep);
|
||||||
|
if (id == 3) throw new Exception("ERROR");
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,6 +184,78 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return () => asyncAction(state).Forget();
|
return () => asyncAction(state).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return (arg) => asyncAction(arg).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return (arg0, arg1) => asyncAction(arg0, arg1).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg, CancellationToken cancellationToken) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return (arg) => asyncAction(arg, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, CancellationToken cancellationToken) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return (arg0, arg1) => asyncAction(arg0, arg1, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, CancellationToken cancellationToken) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken) => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -202,6 +274,22 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask<T>(new DeferPromise<T>(factory), 0);
|
return new UniTask<T>(new DeferPromise<T>(factory), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defer the task creation just before call await.
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask Defer<TState>(TState state, Func<TState, UniTask> factory)
|
||||||
|
{
|
||||||
|
return new UniTask(new DeferPromiseWithState<TState>(state, factory), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defer the task creation just before call await.
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<TResult> Defer<TState, TResult>(TState state, Func<TState, UniTask<TResult>> factory)
|
||||||
|
{
|
||||||
|
return new UniTask<TResult>(new DeferPromiseWithState<TState, TResult>(state, factory), 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Never complete.
|
/// Never complete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -465,6 +553,93 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class DeferPromiseWithState<TState> : IUniTaskSource
|
||||||
|
{
|
||||||
|
Func<TState, UniTask> factory;
|
||||||
|
TState argument;
|
||||||
|
UniTask task;
|
||||||
|
UniTask.Awaiter awaiter;
|
||||||
|
|
||||||
|
public DeferPromiseWithState(TState argument, Func<TState, UniTask> factory)
|
||||||
|
{
|
||||||
|
this.argument = argument;
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
awaiter.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
var f = Interlocked.Exchange(ref factory, null);
|
||||||
|
if (f != null)
|
||||||
|
{
|
||||||
|
task = f(argument);
|
||||||
|
awaiter = task.GetAwaiter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
awaiter.SourceOnCompleted(continuation, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return task.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class DeferPromiseWithState<TState, TResult> : IUniTaskSource<TResult>
|
||||||
|
{
|
||||||
|
Func<TState, UniTask<TResult>> factory;
|
||||||
|
TState argument;
|
||||||
|
UniTask<TResult> task;
|
||||||
|
UniTask<TResult>.Awaiter awaiter;
|
||||||
|
|
||||||
|
public DeferPromiseWithState(TState argument, Func<TState, UniTask<TResult>> factory)
|
||||||
|
{
|
||||||
|
this.argument = argument;
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(short token)
|
||||||
|
{
|
||||||
|
return awaiter.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
awaiter.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
var f = Interlocked.Exchange(ref factory, null);
|
||||||
|
if (f != null)
|
||||||
|
{
|
||||||
|
task = f(argument);
|
||||||
|
awaiter = task.GetAwaiter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
awaiter.SourceOnCompleted(continuation, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return task.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed class NeverPromise<T> : IUniTaskSource<T>
|
sealed class NeverPromise<T> : IUniTaskSource<T>
|
||||||
{
|
{
|
||||||
static readonly Action<object> cancellationCallback = CancellationCallback;
|
static readonly Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|||||||
@@ -15,11 +15,21 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UniTask WaitUntil<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||||
|
{
|
||||||
|
return new UniTask(WaitUntilPromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||||
{
|
{
|
||||||
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UniTask WaitWhile<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||||
|
{
|
||||||
|
return new UniTask(WaitWhilePromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
|
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
|
||||||
{
|
{
|
||||||
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
|
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
|
||||||
@@ -162,6 +172,135 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class WaitUntilPromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise<T>>
|
||||||
|
{
|
||||||
|
static TaskPool<WaitUntilPromise<T>> pool;
|
||||||
|
WaitUntilPromise<T> nextNode;
|
||||||
|
public ref WaitUntilPromise<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
|
static WaitUntilPromise()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<T, bool> predicate;
|
||||||
|
T argument;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
|
WaitUntilPromise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitUntilPromise<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.predicate = predicate;
|
||||||
|
result.argument = argument;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
|
{
|
||||||
|
var promise = (WaitUntilPromise<T>)state;
|
||||||
|
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||||
|
}, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!predicate(argument))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
core.TrySetException(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.TrySetResult(null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
predicate = default;
|
||||||
|
argument = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitWhilePromise> pool;
|
static TaskPool<WaitWhilePromise> pool;
|
||||||
@@ -199,7 +338,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.predicate = predicate;
|
result.predicate = predicate;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.cancelImmediately = cancelImmediately;
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
@@ -288,6 +427,135 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class WaitWhilePromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise<T>>
|
||||||
|
{
|
||||||
|
static TaskPool<WaitWhilePromise<T>> pool;
|
||||||
|
WaitWhilePromise<T> nextNode;
|
||||||
|
public ref WaitWhilePromise<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
|
static WaitWhilePromise()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<T, bool> predicate;
|
||||||
|
T argument;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
|
WaitWhilePromise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitWhilePromise<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.predicate = predicate;
|
||||||
|
result.argument = argument;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
|
{
|
||||||
|
var promise = (WaitWhilePromise<T>)state;
|
||||||
|
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||||
|
}, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (predicate(argument))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
core.TrySetException(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.TrySetResult(null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
predicate = default;
|
||||||
|
argument = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||||
@@ -443,7 +711,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.cancelImmediately = cancelImmediately;
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
@@ -586,7 +854,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.cancelImmediately = cancelImmediately;
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
|
|||||||
183
src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
183
src/UniTask/Assets/Plugins/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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7cac24fdda5112047a1cd3dd66b542c4
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
||||||
"version": "2.5.6",
|
"version": "2.5.8",
|
||||||
"unity": "2018.4",
|
"unity": "2018.4",
|
||||||
"description": "Provides an efficient async/await integration to Unity.",
|
"description": "Provides an efficient async/await integration to Unity.",
|
||||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||||
|
|||||||
@@ -119,7 +119,28 @@ public class AsyncMessageBroker<T> : IDisposable
|
|||||||
connection.Dispose();
|
connection.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public class WhenEachTest
|
||||||
|
{
|
||||||
|
public async UniTask Each()
|
||||||
|
{
|
||||||
|
var a = Delay(1, 3000);
|
||||||
|
var b = Delay(2, 1000);
|
||||||
|
var c = Delay(3, 2000);
|
||||||
|
|
||||||
|
var l = new List<int>();
|
||||||
|
await foreach (var item in UniTask.WhenEach(a, b, c))
|
||||||
|
{
|
||||||
|
Debug.Log(item.Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTask<int> Delay(int id, int sleep)
|
||||||
|
{
|
||||||
|
await UniTask.Delay(sleep);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public class SandboxMain : MonoBehaviour
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -147,6 +168,18 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
Debug.Log("Again");
|
Debug.Log("Again");
|
||||||
|
|
||||||
|
|
||||||
|
// var foo = InstantiateAsync<SandboxMain>(this).ToUniTask();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var tako = await foo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,6 +590,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
|
await new WhenEachTest().Each();
|
||||||
|
|
||||||
|
|
||||||
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
|
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ OcclusionCullingSettings:
|
|||||||
--- !u!104 &2
|
--- !u!104 &2
|
||||||
RenderSettings:
|
RenderSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 9
|
serializedVersion: 10
|
||||||
m_Fog: 0
|
m_Fog: 0
|
||||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
m_FogMode: 3
|
m_FogMode: 3
|
||||||
@@ -43,7 +43,6 @@ RenderSettings:
|
|||||||
LightmapSettings:
|
LightmapSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 12
|
serializedVersion: 12
|
||||||
m_GIWorkflowMode: 1
|
|
||||||
m_GISettings:
|
m_GISettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_BounceScale: 1
|
m_BounceScale: 1
|
||||||
@@ -66,9 +65,6 @@ LightmapSettings:
|
|||||||
m_LightmapParameters: {fileID: 0}
|
m_LightmapParameters: {fileID: 0}
|
||||||
m_LightmapsBakeMode: 1
|
m_LightmapsBakeMode: 1
|
||||||
m_TextureCompression: 1
|
m_TextureCompression: 1
|
||||||
m_FinalGather: 0
|
|
||||||
m_FinalGatherFiltering: 1
|
|
||||||
m_FinalGatherRayCount: 256
|
|
||||||
m_ReflectionCompression: 2
|
m_ReflectionCompression: 2
|
||||||
m_MixedBakeMode: 2
|
m_MixedBakeMode: 2
|
||||||
m_BakeBackend: 0
|
m_BakeBackend: 0
|
||||||
@@ -719,7 +715,6 @@ GameObject:
|
|||||||
- component: {fileID: 1556045507}
|
- component: {fileID: 1556045507}
|
||||||
- component: {fileID: 1556045506}
|
- component: {fileID: 1556045506}
|
||||||
- component: {fileID: 1556045505}
|
- component: {fileID: 1556045505}
|
||||||
- component: {fileID: 1556045509}
|
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Canvas
|
m_Name: Canvas
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
@@ -812,18 +807,6 @@ RectTransform:
|
|||||||
m_AnchoredPosition: {x: 0, y: 0}
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
m_SizeDelta: {x: 0, y: 0}
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
m_Pivot: {x: 0, y: 0}
|
m_Pivot: {x: 0, y: 0}
|
||||||
--- !u!114 &1556045509
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1556045504}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: a478e5f6126dc184ca902adfb35401b4, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
--- !u!1 &1584557231
|
--- !u!1 &1584557231
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -145,6 +145,11 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
public int MyProperty { get; set; }
|
public int MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MyBooleanClass
|
||||||
|
{
|
||||||
|
public bool MyProperty { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
@@ -159,6 +164,20 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
diff.Should().Be(11);
|
diff.Should().Be(11);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WaitUntilWithState() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var v = new MyBooleanClass { MyProperty = false };
|
||||||
|
|
||||||
|
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = true).Forget();
|
||||||
|
|
||||||
|
var startFrame = Time.frameCount;
|
||||||
|
await UniTask.WaitUntil(v, static v => v.MyProperty, PlayerLoopTiming.EarlyUpdate);
|
||||||
|
|
||||||
|
var diff = Time.frameCount - startFrame;
|
||||||
|
diff.Should().Be(11);
|
||||||
|
});
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
@@ -173,6 +192,20 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
diff.Should().Be(11);
|
diff.Should().Be(11);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WaitWhileWithState() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var v = new MyBooleanClass { MyProperty = true };
|
||||||
|
|
||||||
|
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = false).Forget();
|
||||||
|
|
||||||
|
var startFrame = Time.frameCount;
|
||||||
|
await UniTask.WaitWhile(v, static v => v.MyProperty, PlayerLoopTiming.EarlyUpdate);
|
||||||
|
|
||||||
|
var diff = Time.frameCount - startFrame;
|
||||||
|
diff.Should().Be(11);
|
||||||
|
});
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Cysharp.Threading.Tasks;
|
#pragma warning disable CS0618
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
using Cysharp.Threading.Tasks.Linq;
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
|
#pragma warning disable CS0618
|
||||||
|
|
||||||
|
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|||||||
Reference in New Issue
Block a user