mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-19 13:40:11 +00:00
Compare commits
43 Commits
2.0.7-rc4
...
2.0.12-rc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21bf08a6b3 | ||
|
|
d5db96b913 | ||
|
|
a8455af16d | ||
|
|
2290b14532 | ||
|
|
90c5a6311b | ||
|
|
6e0ad3623b | ||
|
|
005e02a1fa | ||
|
|
10fb8060fa | ||
|
|
35b933730b | ||
|
|
7ab9467069 | ||
|
|
598312ba61 | ||
|
|
985aa5c43a | ||
|
|
10eff95a42 | ||
|
|
d27d6d5d9d | ||
|
|
b8c109848e | ||
|
|
8b7f832c0f | ||
|
|
7cce0f48e5 | ||
|
|
8a56838111 | ||
|
|
ff15e00003 | ||
|
|
f60d2c51fb | ||
|
|
6dfb969015 | ||
|
|
da7e9fc4b3 | ||
|
|
70385c4115 | ||
|
|
51ba740413 | ||
|
|
f3e3ba8864 | ||
|
|
07cf65c1ec | ||
|
|
eca5b1c096 | ||
|
|
c74ce14ad1 | ||
|
|
f59c56506f | ||
|
|
896eef1ee4 | ||
|
|
ec0123eec7 | ||
|
|
78f56b9b33 | ||
|
|
1d88ed85bc | ||
|
|
2b7986da19 | ||
|
|
c3d22968e1 | ||
|
|
0e25122ee2 | ||
|
|
4504d84aa8 | ||
|
|
2b87cadba3 | ||
|
|
21dc83c641 | ||
|
|
3b593f349c | ||
|
|
962c215e3b | ||
|
|
42dcfdbcdc | ||
|
|
6d7e6ec871 |
@@ -1,123 +1,30 @@
|
|||||||
#pragma warning disable 0649
|
#pragma warning disable 0649
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks.Sources;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
public static class UniTaskValueTaskExtensions
|
public static class UniTaskValueTaskExtensions
|
||||||
{
|
{
|
||||||
public static ValueTask AsValueTask(this UniTask task)
|
public static ValueTask AsValueTask(this in UniTask task)
|
||||||
{
|
{
|
||||||
ref var core = ref Unsafe.As<UniTask, UniTaskToValueTask>(ref task);
|
return task;
|
||||||
if (core.source == null)
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValueTask(new UniTaskValueTaskSource(core.source), core.token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValueTask<T> AsValueTask<T>(this UniTask<T> task)
|
public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
|
||||||
{
|
{
|
||||||
ref var core = ref Unsafe.As<UniTask<T>, UniTaskToValueTask<T>>(ref task);
|
return task;
|
||||||
if (core.source == null)
|
|
||||||
{
|
|
||||||
return new ValueTask<T>(core.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValueTask<T>(new UniTaskValueTaskSource<T>(core.source), core.token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UniTaskToValueTask
|
public static UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true)
|
||||||
{
|
{
|
||||||
public IUniTaskSource source;
|
// NOTE: get _obj and _token directly for low overhead conversion but not yet implemented.
|
||||||
public short token;
|
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
class UniTaskValueTaskSource : IValueTaskSource
|
public static UniTask AsUniTask(this ValueTask task, bool useCurrentSynchronizationContext = true)
|
||||||
{
|
{
|
||||||
readonly IUniTaskSource source;
|
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||||
|
|
||||||
public UniTaskValueTaskSource(IUniTaskSource source)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
source.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTaskSourceStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
var status = source.GetStatus(token);
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case UniTaskStatus.Pending:
|
|
||||||
return ValueTaskSourceStatus.Pending;
|
|
||||||
case UniTaskStatus.Succeeded:
|
|
||||||
return ValueTaskSourceStatus.Succeeded;
|
|
||||||
case UniTaskStatus.Faulted:
|
|
||||||
return ValueTaskSourceStatus.Faulted;
|
|
||||||
case UniTaskStatus.Canceled:
|
|
||||||
return ValueTaskSourceStatus.Canceled;
|
|
||||||
default:
|
|
||||||
return (ValueTaskSourceStatus)status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
|
|
||||||
{
|
|
||||||
source.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UniTaskToValueTask<T>
|
|
||||||
{
|
|
||||||
public IUniTaskSource<T> source;
|
|
||||||
public T result;
|
|
||||||
public short token;
|
|
||||||
}
|
|
||||||
|
|
||||||
class UniTaskValueTaskSource<T> : IValueTaskSource<T>
|
|
||||||
{
|
|
||||||
readonly IUniTaskSource<T> source;
|
|
||||||
|
|
||||||
public UniTaskValueTaskSource(IUniTaskSource<T> source)
|
|
||||||
{
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
return source.GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTaskSourceStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
var status = source.GetStatus(token);
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case UniTaskStatus.Pending:
|
|
||||||
return ValueTaskSourceStatus.Pending;
|
|
||||||
case UniTaskStatus.Succeeded:
|
|
||||||
return ValueTaskSourceStatus.Succeeded;
|
|
||||||
case UniTaskStatus.Faulted:
|
|
||||||
return ValueTaskSourceStatus.Faulted;
|
|
||||||
case UniTaskStatus.Canceled:
|
|
||||||
return ValueTaskSourceStatus.Canceled;
|
|
||||||
default:
|
|
||||||
return (ValueTaskSourceStatus)status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
|
|
||||||
{
|
|
||||||
source.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -41,7 +43,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if NETCOREAPP3_1
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||||
|
#else
|
||||||
ThreadPool.UnsafeQueueUserWorkItem(WaitCallbackDelegate, continuation);
|
ThreadPool.UnsafeQueueUserWorkItem(WaitCallbackDelegate, continuation);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +56,47 @@ namespace Cysharp.Threading.Tasks
|
|||||||
((Action)state).Invoke();
|
((Action)state).Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NETCOREAPP3_1
|
||||||
|
|
||||||
|
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||||
|
{
|
||||||
|
static TaskPool<ThreadPoolWorkItem> pool;
|
||||||
|
public ThreadPoolWorkItem NextNode { get; set; }
|
||||||
|
|
||||||
|
static ThreadPoolWorkItem()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(ThreadPoolWorkItem), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Action continuation;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ThreadPoolWorkItem Create(Action continuation)
|
||||||
|
{
|
||||||
|
if (!pool.TryPop(out var item))
|
||||||
|
{
|
||||||
|
item = new ThreadPoolWorkItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.continuation = continuation;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
var call = continuation;
|
||||||
|
continuation = null;
|
||||||
|
if (call != null)
|
||||||
|
{
|
||||||
|
pool.TryPush(this);
|
||||||
|
call.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFrameworks>netcoreapp3.1;netstandard2.1</TargetFrameworks>
|
||||||
<AssemblyName>UniTask</AssemblyName>
|
<AssemblyName>UniTask</AssemblyName>
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
258
src/UniTask.NetCoreSandbox/AllocationCheck.cs
Normal file
258
src/UniTask.NetCoreSandbox/AllocationCheck.cs
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using System.Linq;
|
||||||
|
using BenchmarkDotNet.Configs;
|
||||||
|
using BenchmarkDotNet.Diagnosers;
|
||||||
|
using BenchmarkDotNet.Exporters;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using BenchmarkDotNet.Running;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using PooledAwait;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Cysharp.Threading.Tasks.CompilerServices;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
[Config(typeof(BenchmarkConfig))]
|
||||||
|
public class AllocationCheck
|
||||||
|
{
|
||||||
|
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
|
||||||
|
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
|
||||||
|
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
|
||||||
|
// iterations, so that we're only really measuring the inner loop
|
||||||
|
private const int InnerOps = 1000;
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||||
|
public async Task ViaUniTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
{
|
||||||
|
var a = Core();
|
||||||
|
var b = Core();
|
||||||
|
var c = Core();
|
||||||
|
await a;
|
||||||
|
await b;
|
||||||
|
await c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||||
|
public async Task<int> ViaUniTaskT()
|
||||||
|
{
|
||||||
|
var sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
{
|
||||||
|
var a = Core();
|
||||||
|
var b = Core();
|
||||||
|
var c = Core();
|
||||||
|
sum += await a;
|
||||||
|
sum += await b;
|
||||||
|
sum += await c;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
var a = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||||
|
var b = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||||
|
var c = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||||
|
//[Benchmark]
|
||||||
|
public void ViaUniTaskVoid()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
{
|
||||||
|
Core().Forget();
|
||||||
|
Core().Forget();
|
||||||
|
Core().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo : IAsyncStateMachine
|
||||||
|
{
|
||||||
|
public AsyncUniTaskVoidMethodBuilder builder;
|
||||||
|
public TestAwaiter awaiter;
|
||||||
|
public TestAwaiter awaiterawaiter;
|
||||||
|
|
||||||
|
public int state;
|
||||||
|
|
||||||
|
public void MoveNext()
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
awaiterawaiter = awaiter.GetAwaiter();
|
||||||
|
if (awaiterawaiter.IsCompleted)
|
||||||
|
{
|
||||||
|
goto case 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = 0;
|
||||||
|
builder.AwaitUnsafeOnCompleted(ref awaiterawaiter, ref this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
goto END;
|
||||||
|
}
|
||||||
|
|
||||||
|
END:
|
||||||
|
builder.SetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TaskTestException : Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public void GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
readonly T value;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter<T> GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public T GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
|
||||||
|
{
|
||||||
|
public static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||||
|
|
||||||
|
public static void CreatePoolItems(int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
pool.Enqueue(new ThreadPoolWorkItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Action continuation;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ThreadPoolWorkItem Create(Action continuation)
|
||||||
|
{
|
||||||
|
if (!pool.TryDequeue(out var item))
|
||||||
|
{
|
||||||
|
item = new ThreadPoolWorkItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.continuation = continuation;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
var call = continuation;
|
||||||
|
continuation = null;
|
||||||
|
pool.Enqueue(this);
|
||||||
|
|
||||||
|
call.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
283
src/UniTask.NetCoreSandbox/Benchmark.cs
Normal file
283
src/UniTask.NetCoreSandbox/Benchmark.cs
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using System.Linq;
|
||||||
|
using BenchmarkDotNet.Configs;
|
||||||
|
using BenchmarkDotNet.Diagnosers;
|
||||||
|
using BenchmarkDotNet.Exporters;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using BenchmarkDotNet.Running;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using PooledAwait;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Cysharp.Threading.Tasks.CompilerServices;
|
||||||
|
|
||||||
|
//class Program
|
||||||
|
//{
|
||||||
|
// static void Main(string[] args)
|
||||||
|
// {
|
||||||
|
// var switcher = new BenchmarkSwitcher(new[]
|
||||||
|
// {
|
||||||
|
// typeof(StandardBenchmark)
|
||||||
|
// });
|
||||||
|
|
||||||
|
//#if DEBUG
|
||||||
|
// var b = new StandardBenchmark();
|
||||||
|
|
||||||
|
//#else
|
||||||
|
// switcher.Run(args);
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public class BenchmarkConfig : ManualConfig
|
||||||
|
{
|
||||||
|
public BenchmarkConfig()
|
||||||
|
{
|
||||||
|
AddDiagnoser(MemoryDiagnoser.Default);
|
||||||
|
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1)/*.RunOncePerIteration()*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// borrowed from PooledAwait
|
||||||
|
|
||||||
|
[Config(typeof(BenchmarkConfig))]
|
||||||
|
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
|
||||||
|
[CategoriesColumn]
|
||||||
|
public class ComparisonBenchmarks
|
||||||
|
{
|
||||||
|
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
|
||||||
|
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
|
||||||
|
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
|
||||||
|
// iterations, so that we're only really measuring the inner loop
|
||||||
|
private const int InnerOps = 1000;
|
||||||
|
|
||||||
|
public bool ConfigureAwait { get; set; } = false;
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||||
|
[BenchmarkCategory("Task<T>")]
|
||||||
|
public async Task<int> ViaTaskT()
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async Task<int> Inner(int x, int y)
|
||||||
|
{
|
||||||
|
int i = x;
|
||||||
|
await Task.Yield();
|
||||||
|
i *= y;
|
||||||
|
await Task.Yield();
|
||||||
|
return 5 * i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||||
|
[BenchmarkCategory("Task")]
|
||||||
|
public async Task ViaTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
await Inner().ConfigureAwait(ConfigureAwait);
|
||||||
|
|
||||||
|
static async Task Inner()
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
await Task.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||||
|
[BenchmarkCategory("ValueTask<T>")]
|
||||||
|
public async Task<int> ViaValueTaskT()
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async ValueTask<int> Inner(int x, int y)
|
||||||
|
{
|
||||||
|
int i = x;
|
||||||
|
await Task.Yield();
|
||||||
|
i *= y;
|
||||||
|
await Task.Yield();
|
||||||
|
return 5 * i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||||
|
[BenchmarkCategory("ValueTask")]
|
||||||
|
public async Task ViaValueTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
await Inner().ConfigureAwait(ConfigureAwait);
|
||||||
|
|
||||||
|
static async ValueTask Inner()
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
await Task.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||||
|
[BenchmarkCategory("ValueTask<T>")]
|
||||||
|
public async Task<int> ViaPooledValueTaskT()
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async PooledValueTask<int> Inner(int x, int y)
|
||||||
|
{
|
||||||
|
int i = x;
|
||||||
|
await Task.Yield();
|
||||||
|
i *= y;
|
||||||
|
await Task.Yield();
|
||||||
|
return 5 * i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||||
|
[BenchmarkCategory("ValueTask")]
|
||||||
|
public async Task ViaPooledValueTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
await Inner().ConfigureAwait(ConfigureAwait);
|
||||||
|
|
||||||
|
static async PooledValueTask Inner()
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
await Task.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||||
|
[BenchmarkCategory("Task<T>")]
|
||||||
|
public async Task<int> ViaPooledTaskT()
|
||||||
|
{
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async PooledTask<int> Inner(int x, int y)
|
||||||
|
{
|
||||||
|
int i = x;
|
||||||
|
await Task.Yield();
|
||||||
|
i *= y;
|
||||||
|
await Task.Yield();
|
||||||
|
return 5 * i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||||
|
[BenchmarkCategory("Task")]
|
||||||
|
public async Task ViaPooledTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
await Inner().ConfigureAwait(ConfigureAwait);
|
||||||
|
|
||||||
|
static async PooledTask Inner()
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
await Task.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
//[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskVoid")]
|
||||||
|
//[BenchmarkCategory("UniTask")]
|
||||||
|
//public async Task ViaUniTaskVoid()
|
||||||
|
//{
|
||||||
|
// for (int i = 0; i < InnerOps; i++)
|
||||||
|
// {
|
||||||
|
// await Inner();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static async UniTaskVoid Inner()
|
||||||
|
// {
|
||||||
|
// await UniTask.Yield();
|
||||||
|
// await UniTask.Yield();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTask")]
|
||||||
|
[BenchmarkCategory("UniTask")]
|
||||||
|
public async Task ViaUniTask()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
{
|
||||||
|
await Inner();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTask Inner()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskT")]
|
||||||
|
[BenchmarkCategory("UniTask")]
|
||||||
|
public async Task<int> ViaUniTaskT()
|
||||||
|
{
|
||||||
|
var sum = 0;
|
||||||
|
for (int i = 0; i < InnerOps; i++)
|
||||||
|
{
|
||||||
|
sum += await Inner(1, 2);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
static async UniTask<int> Inner(int x, int y)
|
||||||
|
{
|
||||||
|
int i = x;
|
||||||
|
await UniTask.Yield();
|
||||||
|
i *= y;
|
||||||
|
await UniTask.Yield();
|
||||||
|
return 5 * i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct MyAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
public MyAwaiter GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => false;
|
||||||
|
|
||||||
|
public void GetResult()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
continuation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
continuation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct MyTestStateMachine : IAsyncStateMachine
|
||||||
|
{
|
||||||
|
public void MoveNext()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,113 @@ namespace NetCoreSandbox
|
|||||||
public string text { get; set; }
|
public string text { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ZeroAllocAsyncAwaitInDotNetCore
|
||||||
|
{
|
||||||
|
public ValueTask<int> NanikaAsync(int x, int y)
|
||||||
|
{
|
||||||
|
return Core(this, x, y);
|
||||||
|
|
||||||
|
static async UniTask<int> Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
|
||||||
|
{
|
||||||
|
// nanika suru...
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(x + y));
|
||||||
|
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class TaskTestException : Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public void GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
readonly T value;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter<T> GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public T GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static partial class UnityUIComponentExtensions
|
public static partial class UnityUIComponentExtensions
|
||||||
{
|
{
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
|
||||||
@@ -88,20 +195,76 @@ namespace NetCoreSandbox
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
|
#if !DEBUG
|
||||||
|
|
||||||
var channel = Channel.CreateSingleConsumerUnbounded<int>();
|
//await new AllocationCheck().ViaUniTaskVoid();
|
||||||
|
//Console.ReadLine();
|
||||||
|
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
|
||||||
|
|
||||||
|
//await new ComparisonBenchmarks().ViaUniTaskT();
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
// await new AllocationCheck().ViaUniTaskVoid();
|
||||||
|
|
||||||
|
// AsyncTest().Forget();
|
||||||
|
|
||||||
|
|
||||||
|
//AsyncTest().Forget();
|
||||||
|
|
||||||
|
// AsyncTest().Forget();
|
||||||
|
|
||||||
|
ThreadPool.SetMinThreads(100, 100);
|
||||||
|
|
||||||
|
//List<UniTask<int>> list = new List<UniTask<int>>();
|
||||||
|
for (int i = 0; i < short.MaxValue; i++)
|
||||||
|
{
|
||||||
|
//// list.Add(AsyncTest());
|
||||||
|
await YieldCore();
|
||||||
|
}
|
||||||
|
//await UniTask.WhenAll(list);
|
||||||
|
|
||||||
|
//Console.WriteLine("TOGO");
|
||||||
|
|
||||||
|
//var a = await AsyncTest();
|
||||||
|
//var b = AsyncTest();
|
||||||
|
//var c = AsyncTest();
|
||||||
|
await YieldCore();
|
||||||
|
|
||||||
|
//await b;
|
||||||
|
//await c;
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPoolMonitor.GetCacheSizeInfo())
|
||||||
|
{
|
||||||
|
Console.WriteLine(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTask YieldCore()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS1998
|
||||||
|
|
||||||
|
|
||||||
|
static async UniTask<int> AsyncTest()
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(true, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning restore CS1998
|
||||||
|
|
||||||
void Foo()
|
void Foo()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
||||||
|
<PackageReference Include="PooledAwait" Version="1.0.49" />
|
||||||
<PackageReference Include="System.Interactive.Async" Version="4.1.1" />
|
<PackageReference Include="System.Interactive.Async" Version="4.1.1" />
|
||||||
<PackageReference Include="System.Reactive" Version="4.4.1" />
|
<PackageReference Include="System.Reactive" Version="4.4.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -51,6 +51,67 @@ namespace NetCoreTests
|
|||||||
|
|
||||||
ar.Should().BeEquivalentTo(new[] { 100, 100, 100, 131, 191 });
|
ar.Should().BeEquivalentTo(new[] { 100, 100, 100, 131, 191 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[Fact]
|
||||||
|
//public async Task StateIteration()
|
||||||
|
//{
|
||||||
|
// var rp = new ReadOnlyAsyncReactiveProperty<int>(99);
|
||||||
|
// var setter = rp.GetSetter();
|
||||||
|
|
||||||
|
// var f = await rp.FirstAsync();
|
||||||
|
// f.Should().Be(99);
|
||||||
|
|
||||||
|
// var array = rp.Take(5).ToArrayAsync();
|
||||||
|
|
||||||
|
// setter(100);
|
||||||
|
// setter(100);
|
||||||
|
// setter(100);
|
||||||
|
// setter(131);
|
||||||
|
|
||||||
|
// var ar = await array;
|
||||||
|
|
||||||
|
// ar.Should().BeEquivalentTo(new[] { 99, 100, 100, 100, 131 });
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[Fact]
|
||||||
|
//public async Task StateWithoutCurrent()
|
||||||
|
//{
|
||||||
|
// var rp = new ReadOnlyAsyncReactiveProperty<int>(99);
|
||||||
|
// var setter = rp.GetSetter();
|
||||||
|
|
||||||
|
// var array = rp.WithoutCurrent().Take(5).ToArrayAsync();
|
||||||
|
// setter(100);
|
||||||
|
// setter(100);
|
||||||
|
// setter(100);
|
||||||
|
// setter(131);
|
||||||
|
// setter(191);
|
||||||
|
|
||||||
|
// var ar = await array;
|
||||||
|
|
||||||
|
// ar.Should().BeEquivalentTo(new[] { 100, 100, 100, 131, 191 });
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void StateFromEnumeration()
|
||||||
|
{
|
||||||
|
var rp = new AsyncReactiveProperty<int>(10);
|
||||||
|
|
||||||
|
var state = rp.ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
|
||||||
|
|
||||||
|
rp.Value = 10;
|
||||||
|
state.Value.Should().Be(10);
|
||||||
|
|
||||||
|
rp.Value = 20;
|
||||||
|
state.Value.Should().Be(20);
|
||||||
|
|
||||||
|
state.Dispose();
|
||||||
|
|
||||||
|
rp.Value = 30;
|
||||||
|
state.Value.Should().Be(20);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -319,5 +319,119 @@ namespace NetCoreTests.Linq
|
|||||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await ys);
|
await Assert.ThrowsAsync<UniTaskTestException>(async () => await ys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CombineLatestOK()
|
||||||
|
{
|
||||||
|
var a = new AsyncReactiveProperty<int>(0);
|
||||||
|
var b = new AsyncReactiveProperty<int>(0);
|
||||||
|
|
||||||
|
var list = new List<(int, int)>();
|
||||||
|
var complete = a.WithoutCurrent().CombineLatest(b.WithoutCurrent(), (x, y) => (x, y)).ForEachAsync(x => list.Add(x));
|
||||||
|
|
||||||
|
list.Count.Should().Be(0);
|
||||||
|
|
||||||
|
a.Value = 10;
|
||||||
|
list.Count.Should().Be(0);
|
||||||
|
|
||||||
|
a.Value = 20;
|
||||||
|
list.Count.Should().Be(0);
|
||||||
|
|
||||||
|
b.Value = 1;
|
||||||
|
list.Count.Should().Be(1);
|
||||||
|
|
||||||
|
list[0].Should().Be((20, 1));
|
||||||
|
|
||||||
|
a.Value = 30;
|
||||||
|
list.Last().Should().Be((30, 1));
|
||||||
|
|
||||||
|
b.Value = 2;
|
||||||
|
list.Last().Should().Be((30, 2));
|
||||||
|
|
||||||
|
a.Dispose();
|
||||||
|
b.Value = 3;
|
||||||
|
list.Last().Should().Be((30, 3));
|
||||||
|
|
||||||
|
b.Dispose();
|
||||||
|
|
||||||
|
await complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CombineLatestLong()
|
||||||
|
{
|
||||||
|
var a = UniTaskAsyncEnumerable.Range(1, 100000);
|
||||||
|
var b = new AsyncReactiveProperty<int>(0);
|
||||||
|
|
||||||
|
var list = new List<(int, int)>();
|
||||||
|
var complete = a.CombineLatest(b.WithoutCurrent(), (x, y) => (x, y)).ForEachAsync(x => list.Add(x));
|
||||||
|
|
||||||
|
b.Value = 1;
|
||||||
|
|
||||||
|
list[0].Should().Be((100000, 1));
|
||||||
|
|
||||||
|
b.Dispose();
|
||||||
|
|
||||||
|
await complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CombineLatestError()
|
||||||
|
{
|
||||||
|
var a = new AsyncReactiveProperty<int>(0);
|
||||||
|
var b = new AsyncReactiveProperty<int>(0);
|
||||||
|
|
||||||
|
var list = new List<(int, int)>();
|
||||||
|
var complete = a.WithoutCurrent()
|
||||||
|
.Select(x => { if (x == 0) { throw new MyException(); } return x; })
|
||||||
|
.CombineLatest(b.WithoutCurrent(), (x, y) => (x, y)).ForEachAsync(x => list.Add(x));
|
||||||
|
|
||||||
|
|
||||||
|
a.Value = 10;
|
||||||
|
b.Value = 1;
|
||||||
|
list.Last().Should().Be((10, 1));
|
||||||
|
|
||||||
|
a.Value = 0;
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<MyException>(async () => await complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PariwiseImmediate()
|
||||||
|
{
|
||||||
|
var xs = await UniTaskAsyncEnumerable.Range(1, 5).Pairwise().ToArrayAsync();
|
||||||
|
xs.Should().BeEquivalentTo((1, 2), (2, 3), (3, 4), (4, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Pariwise()
|
||||||
|
{
|
||||||
|
var a = new AsyncReactiveProperty<int>(0);
|
||||||
|
|
||||||
|
var list = new List<(int, int)>();
|
||||||
|
var complete = a.WithoutCurrent().Pairwise().ForEachAsync(x => list.Add(x));
|
||||||
|
|
||||||
|
list.Count.Should().Be(0);
|
||||||
|
a.Value = 10;
|
||||||
|
list.Count.Should().Be(0);
|
||||||
|
a.Value = 20;
|
||||||
|
list.Count.Should().Be(1);
|
||||||
|
a.Value = 30;
|
||||||
|
a.Value = 40;
|
||||||
|
a.Value = 50;
|
||||||
|
|
||||||
|
a.Dispose();
|
||||||
|
|
||||||
|
await complete;
|
||||||
|
|
||||||
|
list.Should().BeEquivalentTo((10, 20), (20, 30), (30, 40), (40, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyException : Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
301
src/UniTask.NetCoreTests/TaskBuilderCases.cs
Normal file
301
src/UniTask.NetCoreTests/TaskBuilderCases.cs
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
#pragma warning disable CS1998
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace NetCoreTests
|
||||||
|
{
|
||||||
|
public class UniTaskBuilderTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Empty()
|
||||||
|
{
|
||||||
|
await Core();
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EmptyThrow()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
throw new TaskTestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Done()
|
||||||
|
{
|
||||||
|
await Core();
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(true, UniTaskStatus.Succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Fail()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(true, UniTaskStatus.Faulted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Cancel()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(true, UniTaskStatus.Canceled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetResult()
|
||||||
|
{
|
||||||
|
await Core();
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetException()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Faulted);
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetCancelException()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||||
|
await new TestAwaiter(false, UniTaskStatus.Canceled);
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UniTask_T_BuilderTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Empty()
|
||||||
|
{
|
||||||
|
(await Core()).Should().Be(10);
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EmptyThrow()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
throw new TaskTestException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Done()
|
||||||
|
{
|
||||||
|
(await Core()).Should().Be(10);
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
return await new TestAwaiter<int>(true, UniTaskStatus.Succeeded, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Fail()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
return await new TestAwaiter<int>(true, UniTaskStatus.Faulted, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Task_Cancel()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
return await new TestAwaiter<int>(true, UniTaskStatus.Canceled, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetResult()
|
||||||
|
{
|
||||||
|
(await Core()).Should().Be(6);
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
var sum = 0;
|
||||||
|
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 1);
|
||||||
|
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 2);
|
||||||
|
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 3);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetException()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||||
|
await new TestAwaiter<int>(false, UniTaskStatus.Faulted, 10);
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AwaitUnsafeOnCompletedCall_Task_SetCancelException()
|
||||||
|
{
|
||||||
|
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||||
|
|
||||||
|
static async UniTask<int> Core()
|
||||||
|
{
|
||||||
|
await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||||
|
await new TestAwaiter<int>(false, UniTaskStatus.Canceled, 10);
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TaskTestException : Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public void GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly UniTaskStatus status;
|
||||||
|
readonly bool isCompleted;
|
||||||
|
readonly T value;
|
||||||
|
|
||||||
|
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||||
|
{
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
this.status = status;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestAwaiter<T> GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted => isCompleted;
|
||||||
|
|
||||||
|
public T GetResult()
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case UniTaskStatus.Faulted:
|
||||||
|
throw new TaskTestException();
|
||||||
|
case UniTaskStatus.Canceled:
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
case UniTaskStatus.Pending:
|
||||||
|
case UniTaskStatus.Succeeded:
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/UniTask/Assets/Editor/EditorRunnerChecker.cs
Normal file
30
src/UniTask/Assets/Editor/EditorRunnerChecker.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
|
public static class EditorRunnerChecker
|
||||||
|
{
|
||||||
|
[MenuItem("Tools/UniTaskEditorRunnerChecker")]
|
||||||
|
public static void RunUniTaskAsync()
|
||||||
|
{
|
||||||
|
RunCore().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid RunCore()
|
||||||
|
{
|
||||||
|
Debug.Log("Start");
|
||||||
|
|
||||||
|
var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
|
||||||
|
Debug.Log(r.downloadHandler.text.Substring(0, 100));
|
||||||
|
|
||||||
|
Debug.Log("End");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
11
src/UniTask/Assets/Editor/EditorRunnerChecker.cs.meta
Normal file
11
src/UniTask/Assets/Editor/EditorRunnerChecker.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e51b78c06cb410f42b36e0af9de3b065
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -59,6 +59,24 @@ namespace Cysharp.Threading.Tasks
|
|||||||
triggerEvent.SetCompleted();
|
triggerEvent.SetCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static implicit operator T(AsyncReactiveProperty<T> value)
|
||||||
|
{
|
||||||
|
return value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (isValueType) return latestValue.ToString();
|
||||||
|
return latestValue?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isValueType;
|
||||||
|
|
||||||
|
static AsyncReactiveProperty()
|
||||||
|
{
|
||||||
|
isValueType = typeof(T).IsValueType;
|
||||||
|
}
|
||||||
|
|
||||||
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
readonly AsyncReactiveProperty<T> parent;
|
readonly AsyncReactiveProperty<T> parent;
|
||||||
@@ -156,4 +174,198 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ReadOnlyAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IDisposable
|
||||||
|
{
|
||||||
|
TriggerEvent<T> triggerEvent;
|
||||||
|
|
||||||
|
T latestValue;
|
||||||
|
IUniTaskAsyncEnumerator<T> enumerator;
|
||||||
|
|
||||||
|
public T Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return latestValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadOnlyAsyncReactiveProperty(T initialValue, IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
latestValue = initialValue;
|
||||||
|
ConsumeEnumerator(source, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadOnlyAsyncReactiveProperty(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
ConsumeEnumerator(source, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid ConsumeEnumerator(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (await enumerator.MoveNextAsync())
|
||||||
|
{
|
||||||
|
var value = enumerator.Current;
|
||||||
|
this.latestValue = value;
|
||||||
|
triggerEvent.SetResult(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await enumerator.DisposeAsync();
|
||||||
|
enumerator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerable<T> WithoutCurrent()
|
||||||
|
{
|
||||||
|
return new WithoutCurrentEnumerable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new Enumerator(this, cancellationToken, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (enumerator != null)
|
||||||
|
{
|
||||||
|
enumerator.DisposeAsync().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEvent.SetCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator T(ReadOnlyAsyncReactiveProperty<T> value)
|
||||||
|
{
|
||||||
|
return value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (isValueType) return latestValue.ToString();
|
||||||
|
return latestValue?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isValueType;
|
||||||
|
|
||||||
|
static ReadOnlyAsyncReactiveProperty()
|
||||||
|
{
|
||||||
|
isValueType = typeof(T).IsValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||||
|
{
|
||||||
|
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
||||||
|
|
||||||
|
public WithoutCurrentEnumerable(ReadOnlyAsyncReactiveProperty<T> parent)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new Enumerator(parent, cancellationToken, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
|
||||||
|
{
|
||||||
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
T value;
|
||||||
|
bool isDisposed;
|
||||||
|
bool firstCall;
|
||||||
|
|
||||||
|
public Enumerator(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
this.firstCall = publishCurrentValue;
|
||||||
|
|
||||||
|
parent.triggerEvent.Add(this);
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
|
||||||
|
if (cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Current => value;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
// raise latest value on first call.
|
||||||
|
if (firstCall)
|
||||||
|
{
|
||||||
|
firstCall = false;
|
||||||
|
value = parent.Value;
|
||||||
|
return CompletedTasks.True;
|
||||||
|
}
|
||||||
|
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!isDisposed)
|
||||||
|
{
|
||||||
|
isDisposed = true;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
completionSource.TrySetCanceled(cancellationToken);
|
||||||
|
parent.triggerEvent.Remove(this);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNext(T value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCanceled(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted()
|
||||||
|
{
|
||||||
|
completionSource.TrySetResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnError(Exception ex)
|
||||||
|
{
|
||||||
|
completionSource.TrySetException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (Enumerator)state;
|
||||||
|
self.DisposeAsync().Forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StateExtensions
|
||||||
|
{
|
||||||
|
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new ReadOnlyAsyncReactiveProperty<T>(source, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, T initialValue, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new ReadOnlyAsyncReactiveProperty<T>(initialValue, source, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using System;
|
|||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
public struct AsyncUnit : IEquatable<AsyncUnit>
|
public readonly struct AsyncUnit : IEquatable<AsyncUnit>
|
||||||
{
|
{
|
||||||
public static readonly AsyncUnit Default = new AsyncUnit();
|
public static readonly AsyncUnit Default = new AsyncUnit();
|
||||||
|
|
||||||
|
|||||||
@@ -368,8 +368,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
readonly SingleConsumerUnboundedChannelReader parent;
|
readonly SingleConsumerUnboundedChannelReader parent;
|
||||||
CancellationToken cancellationToken1;
|
CancellationToken cancellationToken1;
|
||||||
CancellationToken cancellationToken2;
|
CancellationToken cancellationToken2;
|
||||||
CancellationTokenRegistration CancellationTokenRegistration1;
|
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||||
CancellationTokenRegistration CancellationTokenRegistration2;
|
CancellationTokenRegistration cancellationTokenRegistration2;
|
||||||
|
|
||||||
T current;
|
T current;
|
||||||
bool cacheValue;
|
bool cacheValue;
|
||||||
@@ -395,12 +395,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (this.cancellationToken1.CanBeCanceled)
|
if (this.cancellationToken1.CanBeCanceled)
|
||||||
{
|
{
|
||||||
this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
|
this.cancellationTokenRegistration1 = this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cancellationToken2.CanBeCanceled)
|
if (this.cancellationToken2.CanBeCanceled)
|
||||||
{
|
{
|
||||||
this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
|
this.cancellationTokenRegistration2 = this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
@@ -428,8 +428,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
public UniTask DisposeAsync()
|
public UniTask DisposeAsync()
|
||||||
{
|
{
|
||||||
CancellationTokenRegistration1.Dispose();
|
cancellationTokenRegistration1.Dispose();
|
||||||
CancellationTokenRegistration2.Dispose();
|
cancellationTokenRegistration2.Dispose();
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct AsyncUniTaskMethodBuilder
|
public struct AsyncUniTaskMethodBuilder
|
||||||
{
|
{
|
||||||
// cache items.
|
internal IMoveNextRunnerPromise runnerPromise;
|
||||||
AutoResetUniTaskCompletionSource promise;
|
Exception ex;
|
||||||
IMoveNextRunner runner;
|
|
||||||
|
|
||||||
// 1. Static Create method.
|
// 1. Static Create method.
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
@@ -31,18 +30,18 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (promise != null)
|
if (runnerPromise != null)
|
||||||
{
|
{
|
||||||
return promise.Task;
|
return runnerPromise.Task;
|
||||||
}
|
}
|
||||||
|
else if (ex != null)
|
||||||
if (runner == null)
|
{
|
||||||
|
return UniTask.FromException(ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return UniTask.CompletedTask;
|
return UniTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = AutoResetUniTaskCompletionSource.Create();
|
|
||||||
return promise.Task;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,20 +49,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public void SetException(Exception exception)
|
public void SetException(Exception exception)
|
||||||
{
|
{
|
||||||
// runner is finished, return first.
|
if (runnerPromise == null)
|
||||||
if (runner != null)
|
|
||||||
{
|
{
|
||||||
runner.Return();
|
ex = exception;
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promise != null)
|
|
||||||
{
|
|
||||||
promise.TrySetException(exception);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
promise = AutoResetUniTaskCompletionSource.CreateFromException(exception, out _);
|
runnerPromise.SetException(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,16 +63,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public void SetResult()
|
public void SetResult()
|
||||||
{
|
{
|
||||||
// runner is finished, return first.
|
if (runnerPromise != null)
|
||||||
if (runner != null)
|
|
||||||
{
|
{
|
||||||
runner.Return();
|
runnerPromise.SetResult();
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promise != null)
|
|
||||||
{
|
|
||||||
promise.TrySetResult();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,16 +75,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
where TAwaiter : INotifyCompletion
|
where TAwaiter : INotifyCompletion
|
||||||
where TStateMachine : IAsyncStateMachine
|
where TStateMachine : IAsyncStateMachine
|
||||||
{
|
{
|
||||||
if (promise == null)
|
if (runnerPromise == null)
|
||||||
{
|
{
|
||||||
promise = AutoResetUniTaskCompletionSource.Create();
|
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.OnCompleted(runnerPromise.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
// 6. AwaitUnsafeOnCompleted
|
||||||
@@ -109,16 +90,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
where TAwaiter : ICriticalNotifyCompletion
|
where TAwaiter : ICriticalNotifyCompletion
|
||||||
where TStateMachine : IAsyncStateMachine
|
where TStateMachine : IAsyncStateMachine
|
||||||
{
|
{
|
||||||
if (promise == null)
|
if (runnerPromise == null)
|
||||||
{
|
{
|
||||||
promise = AutoResetUniTaskCompletionSource.Create();
|
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Start
|
// 7. Start
|
||||||
@@ -156,9 +133,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct AsyncUniTaskMethodBuilder<T>
|
public struct AsyncUniTaskMethodBuilder<T>
|
||||||
{
|
{
|
||||||
// cache items.
|
internal IMoveNextRunnerPromise<T> runnerPromise;
|
||||||
AutoResetUniTaskCompletionSource<T> promise;
|
Exception ex;
|
||||||
IMoveNextRunner runner;
|
|
||||||
T result;
|
T result;
|
||||||
|
|
||||||
// 1. Static Create method.
|
// 1. Static Create method.
|
||||||
@@ -175,18 +151,18 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (promise != null)
|
if (runnerPromise != null)
|
||||||
{
|
{
|
||||||
return promise.Task;
|
return runnerPromise.Task;
|
||||||
}
|
}
|
||||||
|
else if (ex != null)
|
||||||
if (runner == null)
|
{
|
||||||
|
return UniTask.FromException<T>(ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return UniTask.FromResult(result);
|
return UniTask.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
|
||||||
return promise.Task;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,20 +170,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public void SetException(Exception exception)
|
public void SetException(Exception exception)
|
||||||
{
|
{
|
||||||
// runner is finished, return first.
|
if (runnerPromise == null)
|
||||||
if (runner != null)
|
|
||||||
{
|
{
|
||||||
runner.Return();
|
ex = exception;
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promise == null)
|
|
||||||
{
|
|
||||||
promise = AutoResetUniTaskCompletionSource<T>.CreateFromException(exception, out _);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
promise.TrySetException(exception);
|
runnerPromise.SetException(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,20 +184,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public void SetResult(T result)
|
public void SetResult(T result)
|
||||||
{
|
{
|
||||||
// runner is finished, return first.
|
if (runnerPromise == null)
|
||||||
if (runner != null)
|
|
||||||
{
|
|
||||||
runner.Return();
|
|
||||||
runner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (promise == null)
|
|
||||||
{
|
{
|
||||||
this.result = result;
|
this.result = result;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
promise.TrySetResult(result);
|
{
|
||||||
|
runnerPromise.SetResult(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. AwaitOnCompleted
|
// 5. AwaitOnCompleted
|
||||||
@@ -237,16 +200,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
where TAwaiter : INotifyCompletion
|
where TAwaiter : INotifyCompletion
|
||||||
where TStateMachine : IAsyncStateMachine
|
where TStateMachine : IAsyncStateMachine
|
||||||
{
|
{
|
||||||
if (promise == null)
|
if (runnerPromise == null)
|
||||||
{
|
{
|
||||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.OnCompleted(runnerPromise.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
// 6. AwaitUnsafeOnCompleted
|
||||||
@@ -256,16 +215,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
where TAwaiter : ICriticalNotifyCompletion
|
where TAwaiter : ICriticalNotifyCompletion
|
||||||
where TStateMachine : IAsyncStateMachine
|
where TStateMachine : IAsyncStateMachine
|
||||||
{
|
{
|
||||||
if (promise == null)
|
if (runnerPromise == null)
|
||||||
{
|
{
|
||||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
|
||||||
if (runner == null)
|
|
||||||
{
|
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Start
|
// 7. Start
|
||||||
|
|||||||
@@ -4,13 +4,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||||
{
|
{
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct AsyncUniTaskVoidMethodBuilder
|
public struct AsyncUniTaskVoidMethodBuilder
|
||||||
{
|
{
|
||||||
IMoveNextRunner runner;
|
internal IMoveNextRunner runner;
|
||||||
|
|
||||||
// 1. Static Create method.
|
// 1. Static Create method.
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
@@ -65,10 +67,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
if (runner == null)
|
if (runner == null)
|
||||||
{
|
{
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.OnCompleted(runner.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. AwaitUnsafeOnCompleted
|
// 6. AwaitUnsafeOnCompleted
|
||||||
@@ -80,10 +82,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
if (runner == null)
|
if (runner == null)
|
||||||
{
|
{
|
||||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
awaiter.OnCompleted(runner.CallMoveNext);
|
awaiter.UnsafeOnCompleted(runner.MoveNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Start
|
// 7. Start
|
||||||
|
|||||||
@@ -1,56 +1,327 @@
|
|||||||
|
#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 Cysharp.Threading.Tasks.Internal;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||||
{
|
{
|
||||||
internal interface IMoveNextRunner
|
public interface IMoveNextRunner
|
||||||
{
|
{
|
||||||
Action CallMoveNext { get; }
|
Action MoveNext { get; }
|
||||||
void Return();
|
void Return();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class MoveNextRunner<TStateMachine> : IMoveNextRunner, IPromisePoolItem
|
internal interface IMoveNextRunnerPromise : IUniTaskSource
|
||||||
|
{
|
||||||
|
Action MoveNext { get; }
|
||||||
|
UniTask Task { get; }
|
||||||
|
void SetResult();
|
||||||
|
void SetException(Exception exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IMoveNextRunnerPromise<T> : IUniTaskSource<T>
|
||||||
|
{
|
||||||
|
Action MoveNext { get; }
|
||||||
|
UniTask<T> Task { get; }
|
||||||
|
void SetResult(T result);
|
||||||
|
void SetException(Exception exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class AsyncUniTaskVoid<TStateMachine> : IMoveNextRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
|
||||||
where TStateMachine : IAsyncStateMachine
|
where TStateMachine : IAsyncStateMachine
|
||||||
{
|
{
|
||||||
static PromisePool<MoveNextRunner<TStateMachine>> pool = new PromisePool<MoveNextRunner<TStateMachine>>();
|
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
TStateMachine stateMachine;
|
||||||
internal readonly Action callMoveNext;
|
|
||||||
|
|
||||||
public Action CallMoveNext => callMoveNext;
|
public Action MoveNext { get; }
|
||||||
|
|
||||||
MoveNextRunner()
|
public AsyncUniTaskVoid()
|
||||||
{
|
{
|
||||||
callMoveNext = MoveNext;
|
MoveNext = Run;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MoveNextRunner<TStateMachine> Create(ref TStateMachine stateMachine)
|
public static void SetStateMachine(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine)
|
||||||
{
|
{
|
||||||
var result = pool.TryRent() ?? new MoveNextRunner<TStateMachine>();
|
if (!pool.TryPop(out var result))
|
||||||
result.stateMachine = stateMachine;
|
{
|
||||||
return result;
|
result = new AsyncUniTaskVoid<TStateMachine>();
|
||||||
|
}
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
builder.runner = result; // set runner before copied.
|
||||||
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
|
}
|
||||||
|
|
||||||
|
static AsyncUniTaskVoid()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncUniTaskVoid<TStateMachine> NextNode { get; set; }
|
||||||
|
|
||||||
|
public void Return()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
stateMachine = default;
|
||||||
|
pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void MoveNext()
|
void Run()
|
||||||
{
|
{
|
||||||
stateMachine.MoveNext();
|
stateMachine.MoveNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Return()
|
// dummy interface implementation for TaskTracker.
|
||||||
|
|
||||||
|
UniTaskStatus IUniTaskSource.GetStatus(short token)
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
return UniTaskStatus.Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPromisePoolItem.Reset()
|
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
|
||||||
{
|
{
|
||||||
|
return UniTaskStatus.Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class AsyncUniTask<TStateMachine> : IMoveNextRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
|
||||||
|
where TStateMachine : IAsyncStateMachine
|
||||||
|
{
|
||||||
|
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
||||||
|
|
||||||
|
TStateMachine stateMachine;
|
||||||
|
|
||||||
|
public Action MoveNext { get; }
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
|
AsyncUniTask()
|
||||||
|
{
|
||||||
|
MoveNext = Run;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine)
|
||||||
|
{
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncUniTask<TStateMachine>();
|
||||||
|
}
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
builder.runnerPromise = result; // set runner before copied.
|
||||||
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncUniTask<TStateMachine> NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncUniTask()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
stateMachine = default;
|
stateMachine = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
void Run()
|
||||||
|
{
|
||||||
|
stateMachine.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask Task
|
||||||
|
{
|
||||||
|
[DebuggerHidden]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new UniTask(this, core.Version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void SetResult()
|
||||||
|
{
|
||||||
|
core.TrySetResult(AsyncUnit.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void SetException(Exception exception)
|
||||||
|
{
|
||||||
|
core.TrySetException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncUniTask()
|
||||||
|
{
|
||||||
|
if (TryReturn())
|
||||||
|
{
|
||||||
|
GC.ReRegisterForFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class AsyncUniTask<TStateMachine, T> : IMoveNextRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
|
||||||
|
where TStateMachine : IAsyncStateMachine
|
||||||
|
{
|
||||||
|
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
||||||
|
|
||||||
|
TStateMachine stateMachine;
|
||||||
|
|
||||||
|
public Action MoveNext { get; }
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<T> core;
|
||||||
|
|
||||||
|
AsyncUniTask()
|
||||||
|
{
|
||||||
|
MoveNext = Run;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine)
|
||||||
|
{
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncUniTask<TStateMachine, T>();
|
||||||
|
}
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
builder.runnerPromise = result; // set runner before copied.
|
||||||
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncUniTask()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
stateMachine = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
void Run()
|
||||||
|
{
|
||||||
|
stateMachine.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask<T> Task
|
||||||
|
{
|
||||||
|
[DebuggerHidden]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new UniTask<T>(this, core.Version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void SetResult(T result)
|
||||||
|
{
|
||||||
|
core.TrySetResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void SetException(Exception exception)
|
||||||
|
{
|
||||||
|
core.TrySetException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public T GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncUniTask()
|
||||||
|
{
|
||||||
|
if (TryReturn())
|
||||||
|
{
|
||||||
|
GC.ReRegisterForFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,22 +14,31 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static UniTask.Awaiter GetAwaiter(this IEnumerator enumerator)
|
public static UniTask.Awaiter GetAwaiter(this IEnumerator enumerator)
|
||||||
{
|
{
|
||||||
|
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
|
||||||
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
|
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this IEnumerator enumerator)
|
public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, CancellationToken.None, out var token), token);
|
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
|
||||||
|
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ConfigureAwait(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
public static UniTask ToUniTask(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
|
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
|
||||||
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
|
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<EnumeratorPromise> pool = new PromisePool<EnumeratorPromise>();
|
static TaskPool<EnumeratorPromise> pool;
|
||||||
|
public EnumeratorPromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static EnumeratorPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerator innerEnumerator;
|
IEnumerator innerEnumerator;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
@@ -47,13 +56,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new EnumeratorPromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new EnumeratorPromise();
|
||||||
|
}
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
token = result.core.Version;
|
token = result.core.Version;
|
||||||
@@ -64,12 +75,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,16 +123,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
innerEnumerator = default;
|
innerEnumerator = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~EnumeratorPromise()
|
~EnumeratorPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,21 +13,23 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static class AddressableAsyncExtensions
|
public static class AddressableAsyncExtensions
|
||||||
{
|
{
|
||||||
#region AsyncOperationHandle
|
#region AsyncOperationHandle
|
||||||
|
|
||||||
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
|
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||||
{
|
{
|
||||||
return new AsyncOperationHandleAwaiter(handle);
|
return new AsyncOperationHandleAwaiter(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this AsyncOperationHandle handle)
|
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
if (handle.IsDone) return UniTask.CompletedTask;
|
||||||
|
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ConfigureAwait(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellation, out var token), token);
|
if (handle.IsDone) return UniTask.CompletedTask;
|
||||||
|
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -70,14 +72,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||||
handle.Completed += continuationAction;
|
handle.Completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AsyncOperationHandleConfiguredSource> pool = new PromisePool<AsyncOperationHandleConfiguredSource>();
|
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||||
|
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncOperationHandleConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
AsyncOperationHandle handle;
|
AsyncOperationHandle handle;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -97,7 +105,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new AsyncOperationHandleConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncOperationHandleConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.handle = handle;
|
result.handle = handle;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -115,12 +126,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,40 +179,44 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
core.Reset();
|
core.Reset();
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
handle = default;
|
handle = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AsyncOperationHandleConfiguredSource()
|
~AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AsyncOperationHandle_T
|
#region AsyncOperationHandle_T
|
||||||
|
|
||||||
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||||
{
|
{
|
||||||
return new AsyncOperationHandleAwaiter<T>(handle);
|
return new AsyncOperationHandleAwaiter<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle)
|
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||||
|
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<T> ConfigureAwait<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellation, out var token), token);
|
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||||
|
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
||||||
@@ -245,14 +260,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||||
handle.CompletedTypeless += continuationAction;
|
handle.CompletedTypeless += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, IPromisePoolItem
|
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AsyncOperationHandleConfiguredSource<T>> pool = new PromisePool<AsyncOperationHandleConfiguredSource<T>>();
|
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||||
|
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncOperationHandleConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
AsyncOperationHandle<T> handle;
|
AsyncOperationHandle<T> handle;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -272,7 +293,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new AsyncOperationHandleConfiguredSource<T>();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||||
|
}
|
||||||
|
|
||||||
result.handle = handle;
|
result.handle = handle;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -290,13 +314,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,24 +371,26 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
handle = default;
|
handle = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AsyncOperationHandleConfiguredSource()
|
~AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
290
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DoTweenAsyncExtensions.cs
vendored
Normal file
290
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DoTweenAsyncExtensions.cs
vendored
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
// asmdef Version Defines, enabled when com.demigiant.dotween is imported.
|
||||||
|
|
||||||
|
#if UNITASK_DOTWEEN_SUPPORT
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using DG.Tweening;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
// The idea of TweenCancelBehaviour is borrowed from https://www.shibuya24.info/entry/dotween_async_await
|
||||||
|
public enum TweenCancelBehaviour
|
||||||
|
{
|
||||||
|
Kill,
|
||||||
|
KillWithCompleteCallback,
|
||||||
|
Complete,
|
||||||
|
CompleteWithSeqeunceCallback,
|
||||||
|
CancelAwait,
|
||||||
|
|
||||||
|
// AndCancelAwait
|
||||||
|
KillAndCancelAwait,
|
||||||
|
KillWithCompleteCallbackAndCancelAwait,
|
||||||
|
CompleteAndCancelAwait,
|
||||||
|
CompleteWithSeqeunceCallbackAndCancelAwait
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DOTweenAsyncExtensions
|
||||||
|
{
|
||||||
|
public static TweenAwaiter GetAwaiter(this Tween tween)
|
||||||
|
{
|
||||||
|
return new TweenAwaiter(tween);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||||
|
|
||||||
|
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||||
|
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||||
|
|
||||||
|
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||||
|
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TweenAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
readonly Tween tween;
|
||||||
|
|
||||||
|
// killed(non active) as completed.
|
||||||
|
public bool IsCompleted => !tween.IsActive();
|
||||||
|
|
||||||
|
public TweenAwaiter(Tween tween)
|
||||||
|
{
|
||||||
|
this.tween = tween;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TweenAwaiter GetAwaiter()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(System.Action continuation)
|
||||||
|
{
|
||||||
|
UnsafeOnCompleted(continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(System.Action continuation)
|
||||||
|
{
|
||||||
|
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
|
||||||
|
tween.onKill = PooledTweenCallback.Create(continuation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
||||||
|
{
|
||||||
|
static TaskPool<TweenConfiguredSource> pool;
|
||||||
|
public TweenConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static TweenConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
|
||||||
|
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||||
|
|
||||||
|
readonly TweenCallback onKillDelegate;
|
||||||
|
|
||||||
|
Tween tween;
|
||||||
|
TweenCancelBehaviour cancelBehaviour;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
bool canceled;
|
||||||
|
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
|
TweenConfiguredSource()
|
||||||
|
{
|
||||||
|
onKillDelegate = OnKill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new TweenConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.tween = tween;
|
||||||
|
result.cancelBehaviour = cancelBehaviour;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
result.RegisterEvent();
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterEvent()
|
||||||
|
{
|
||||||
|
if (cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
tween.OnKill(onKillDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnKill()
|
||||||
|
{
|
||||||
|
cancellationTokenRegistration.Dispose();
|
||||||
|
if (canceled)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
core.TrySetResult(AsyncUnit.Default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (TweenConfiguredSource)state;
|
||||||
|
|
||||||
|
switch (self.cancelBehaviour)
|
||||||
|
{
|
||||||
|
case TweenCancelBehaviour.Kill:
|
||||||
|
default:
|
||||||
|
self.tween.Kill(false);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.KillAndCancelAwait:
|
||||||
|
self.canceled = true;
|
||||||
|
self.tween.Kill(false);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.KillWithCompleteCallback:
|
||||||
|
self.tween.Kill(true);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
|
||||||
|
self.canceled = true;
|
||||||
|
self.tween.Kill(true);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.Complete:
|
||||||
|
self.tween.Complete(false);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
||||||
|
self.canceled = true;
|
||||||
|
self.tween.Complete(false);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
|
||||||
|
self.tween.Complete(true);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
|
||||||
|
self.canceled = true;
|
||||||
|
self.tween.Complete(true);
|
||||||
|
break;
|
||||||
|
case TweenCancelBehaviour.CancelAwait:
|
||||||
|
self.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Caceled(instance is returned to pool.)
|
||||||
|
self.core.TrySetCanceled(self.cancellationToken);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
tween = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~TweenConfiguredSource()
|
||||||
|
{
|
||||||
|
if (TryReturn())
|
||||||
|
{
|
||||||
|
GC.ReRegisterForFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class PooledTweenCallback
|
||||||
|
{
|
||||||
|
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
|
||||||
|
|
||||||
|
readonly TweenCallback runDelegate;
|
||||||
|
|
||||||
|
Action continuation;
|
||||||
|
|
||||||
|
|
||||||
|
PooledTweenCallback()
|
||||||
|
{
|
||||||
|
runDelegate = Run;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TweenCallback Create(Action continuation)
|
||||||
|
{
|
||||||
|
if (!pool.TryDequeue(out var item))
|
||||||
|
{
|
||||||
|
item = new PooledTweenCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.continuation = continuation;
|
||||||
|
return item.runDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
void Run()
|
||||||
|
{
|
||||||
|
var call = continuation;
|
||||||
|
continuation = null;
|
||||||
|
if (call != null)
|
||||||
|
{
|
||||||
|
pool.Enqueue(this);
|
||||||
|
call.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
11
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DoTweenAsyncExtensions.cs.meta
vendored
Normal file
11
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DoTweenAsyncExtensions.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1f448d5bc5b232e4f98d89d5d1832e8e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -19,17 +19,75 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
// similar as IValueTaskSource
|
// similar as IValueTaskSource
|
||||||
public interface IUniTaskSource
|
public interface IUniTaskSource
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
: System.Threading.Tasks.Sources.IValueTaskSource
|
||||||
|
#pragma warning disable CS0108
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
UniTaskStatus GetStatus(short token);
|
UniTaskStatus GetStatus(short token);
|
||||||
void OnCompleted(Action<object> continuation, object state, short token);
|
void OnCompleted(Action<object> continuation, object state, short token);
|
||||||
void GetResult(short token);
|
void GetResult(short token);
|
||||||
|
|
||||||
UniTaskStatus UnsafeGetStatus(); // only for debug use.
|
UniTaskStatus UnsafeGetStatus(); // only for debug use.
|
||||||
|
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
#pragma warning restore CS0108
|
||||||
|
|
||||||
|
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
|
||||||
|
{
|
||||||
|
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
((IUniTaskSource)this).GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System.Threading.Tasks.Sources.IValueTaskSource.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
||||||
|
{
|
||||||
|
// ignore flags, always none.
|
||||||
|
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IUniTaskSource<out T> : IUniTaskSource
|
public interface IUniTaskSource<out T> : IUniTaskSource
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
, System.Threading.Tasks.Sources.IValueTaskSource<T>
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
new T GetResult(short token);
|
new T GetResult(short token);
|
||||||
|
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
new public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return ((IUniTaskSource)this).GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
new public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource<T>.GetStatus(short token)
|
||||||
|
{
|
||||||
|
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
T System.Threading.Tasks.Sources.IValueTaskSource<T>.GetResult(short token)
|
||||||
|
{
|
||||||
|
return ((IUniTaskSource<T>)this).GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System.Threading.Tasks.Sources.IValueTaskSource<T>.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
||||||
|
{
|
||||||
|
// ignore flags, always none.
|
||||||
|
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UniTaskStatusExtensions
|
public static class UniTaskStatusExtensions
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Internal
|
||||||
|
{
|
||||||
|
internal sealed class PooledDelegate<T> : ITaskPoolNode<PooledDelegate<T>>
|
||||||
|
{
|
||||||
|
static TaskPool<PooledDelegate<T>> pool;
|
||||||
|
|
||||||
|
public PooledDelegate<T> NextNode { get; set; }
|
||||||
|
|
||||||
|
static PooledDelegate()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(PooledDelegate<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly Action<T> runDelegate;
|
||||||
|
Action continuation;
|
||||||
|
|
||||||
|
PooledDelegate()
|
||||||
|
{
|
||||||
|
runDelegate = Run;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Action<T> Create(Action continuation)
|
||||||
|
{
|
||||||
|
if (!pool.TryPop(out var item))
|
||||||
|
{
|
||||||
|
item = new PooledDelegate<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.continuation = continuation;
|
||||||
|
return item.runDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
void Run(T _)
|
||||||
|
{
|
||||||
|
var call = continuation;
|
||||||
|
continuation = null;
|
||||||
|
if (call != null)
|
||||||
|
{
|
||||||
|
pool.TryPush(this);
|
||||||
|
call.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8932579438742fa40b010edd412dbfba
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Internal
|
|
||||||
{
|
|
||||||
// public, allow to user create custom operator with pool.
|
|
||||||
|
|
||||||
public interface IPromisePoolItem
|
|
||||||
{
|
|
||||||
void Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PromisePool<T>
|
|
||||||
where T : class, IPromisePoolItem
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
readonly ConcurrentQueue<T> queue = new ConcurrentQueue<T>();
|
|
||||||
readonly int maxSize;
|
|
||||||
|
|
||||||
public PromisePool(int maxSize = 256)
|
|
||||||
{
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public T TryRent()
|
|
||||||
{
|
|
||||||
if (queue.TryDequeue(out var value))
|
|
||||||
{
|
|
||||||
Interlocked.Decrement(ref count);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryReturn(T value)
|
|
||||||
{
|
|
||||||
value.Reset(); // reset when return.
|
|
||||||
|
|
||||||
if (count < maxSize)
|
|
||||||
{
|
|
||||||
queue.Enqueue(value);
|
|
||||||
Interlocked.Increment(ref count);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
119
src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/TaskPool.cs
Normal file
119
src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/TaskPool.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Internal
|
||||||
|
{
|
||||||
|
// internaly used but public, allow to user create custom operator with pooling.
|
||||||
|
|
||||||
|
public static class TaskPool
|
||||||
|
{
|
||||||
|
internal static int MaxPoolSize;
|
||||||
|
|
||||||
|
static TaskPool()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = Environment.GetEnvironmentVariable("UNITASK_MAX_POOLSIZE");
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
if (int.TryParse(value, out var size))
|
||||||
|
{
|
||||||
|
MaxPoolSize = size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
MaxPoolSize = int.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetMaxPoolSize(int maxPoolSize)
|
||||||
|
{
|
||||||
|
MaxPoolSize = maxPoolSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface ITaskPoolNode<T>
|
||||||
|
{
|
||||||
|
T NextNode { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// mutable struct, don't mark readonly.
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct TaskPool<T>
|
||||||
|
where T : class, ITaskPoolNode<T>
|
||||||
|
{
|
||||||
|
int gate;
|
||||||
|
int size;
|
||||||
|
T root;
|
||||||
|
|
||||||
|
public int Size => size;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool TryPop(out T result)
|
||||||
|
{
|
||||||
|
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||||
|
{
|
||||||
|
var v = root;
|
||||||
|
if (!(v is null))
|
||||||
|
{
|
||||||
|
root = v.NextNode;
|
||||||
|
v.NextNode = null;
|
||||||
|
size--;
|
||||||
|
result = v;
|
||||||
|
Volatile.Write(ref gate, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Volatile.Write(ref gate, 0);
|
||||||
|
}
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool TryPush(T item)
|
||||||
|
{
|
||||||
|
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||||
|
{
|
||||||
|
if (size < TaskPool.MaxPoolSize)
|
||||||
|
{
|
||||||
|
item.NextNode = root;
|
||||||
|
root = item;
|
||||||
|
size++;
|
||||||
|
Volatile.Write(ref gate, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Volatile.Write(ref gate, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TaskPoolMonitor
|
||||||
|
{
|
||||||
|
static ConcurrentDictionary<Type, Func<int>> sizes = new ConcurrentDictionary<Type, Func<int>>();
|
||||||
|
|
||||||
|
public static IEnumerable<(Type, int)> GetCacheSizeInfo()
|
||||||
|
{
|
||||||
|
foreach (var item in sizes)
|
||||||
|
{
|
||||||
|
yield return (item.Key, item.Value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterSizeGetter(Type type, Func<int> getSize)
|
||||||
|
{
|
||||||
|
sizes[type] = getSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 19f4e6575150765449cc99f25f06f25f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
|
||||||
@@ -103,16 +104,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
string typeName = null;
|
|
||||||
var keyType = listPool[i].Key.GetType();
|
var keyType = listPool[i].Key.GetType();
|
||||||
if (keyType.IsNested)
|
|
||||||
{
|
var sb = new StringBuilder();
|
||||||
typeName = keyType.DeclaringType.Name + "." + keyType.Name;
|
TypeBeautify(keyType, sb);
|
||||||
}
|
var typeName = sb.ToString();
|
||||||
else
|
|
||||||
{
|
|
||||||
typeName = keyType.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
action(listPool[i].Value.trackingId, typeName, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
|
action(listPool[i].Value.trackingId, typeName, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
|
||||||
listPool[i] = new KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>(null, (0, default(DateTime), null)); // clear
|
listPool[i] = new KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>(null, (0, default(DateTime), null)); // clear
|
||||||
@@ -125,6 +121,31 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TypeBeautify(Type type, StringBuilder sb)
|
||||||
|
{
|
||||||
|
if (type.IsNested)
|
||||||
|
{
|
||||||
|
TypeBeautify(type.DeclaringType, sb);
|
||||||
|
sb.Append(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var genericsStart = type.Name.IndexOf("`");
|
||||||
|
sb.Append(type.Name.Substring(0, genericsStart));
|
||||||
|
sb.Append("<");
|
||||||
|
foreach (var item in type.GetGenericArguments())
|
||||||
|
{
|
||||||
|
TypeBeautify(item, sb);
|
||||||
|
}
|
||||||
|
sb.Append(">");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(type.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11372
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/CombineLatest.cs
Normal file
11372
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/CombineLatest.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6cb07f6e88287e34d9b9301a572284a5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
221
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/CombineLatest.tt
Normal file
221
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/CombineLatest.tt
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ import namespace="System.Linq" #>
|
||||||
|
<#@ import namespace="System.Text" #>
|
||||||
|
<#@ import namespace="System.Collections.Generic" #>
|
||||||
|
<#@ output extension=".cs" #>
|
||||||
|
<#
|
||||||
|
var tMax = 15;
|
||||||
|
Func<int, string> typeArgs = x => string.Join(", ", Enumerable.Range(1, x).Select(x => $"T{x}")) + ", TResult";
|
||||||
|
Func<int, string> paramArgs = x => string.Join(", ", Enumerable.Range(1, x).Select(x => $"IUniTaskAsyncEnumerable<T{x}> source{x}"));
|
||||||
|
Func<int, string> parameters = x => string.Join(", ", Enumerable.Range(1, x).Select(x => $"source{x}"));
|
||||||
|
|
||||||
|
|
||||||
|
#>
|
||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Linq
|
||||||
|
{
|
||||||
|
public static partial class UniTaskAsyncEnumerable
|
||||||
|
{
|
||||||
|
<# for(var i = 2; i <= tMax; i++) { #>
|
||||||
|
public static IUniTaskAsyncEnumerable<TResult> CombineLatest<<#= typeArgs(i) #>>(this <#= paramArgs(i) #>, Func<<#= typeArgs(i) #>> resultSelector)
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
Error.ThrowArgumentNullException(source<#= j #>, nameof(source<#= j #>));
|
||||||
|
<# } #>
|
||||||
|
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||||
|
|
||||||
|
return new CombineLatest<<#= typeArgs(i) #>>(<#= parameters(i) #>, resultSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
|
||||||
|
<# for(var i = 2; i <= tMax; i++) { #>
|
||||||
|
internal class CombineLatest<<#= typeArgs(i) #>> : IUniTaskAsyncEnumerable<TResult>
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
readonly IUniTaskAsyncEnumerable<T<#= j #>> source<#= j #>;
|
||||||
|
<# } #>
|
||||||
|
readonly Func<<#= typeArgs(i) #>> resultSelector;
|
||||||
|
|
||||||
|
public CombineLatest(<#= paramArgs(i) #>, Func<<#= typeArgs(i) #>> resultSelector)
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
this.source<#= j #> = source<#= j #>;
|
||||||
|
<# } #>
|
||||||
|
this.resultSelector = resultSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new _CombineLatest(<#= parameters(i) #>, resultSelector, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CombineLatest : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
static readonly Action<object> Completed<#= j #>Delegate = Completed<#= j #>;
|
||||||
|
<# } #>
|
||||||
|
const int CompleteCount = <#= i #>;
|
||||||
|
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
readonly IUniTaskAsyncEnumerable<T<#= j #>> source<#= j #>;
|
||||||
|
<# } #>
|
||||||
|
readonly Func<<#= typeArgs(i) #>> resultSelector;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
IUniTaskAsyncEnumerator<T<#= j #>> enumerator<#= j #>;
|
||||||
|
UniTask<bool>.Awaiter awaiter<#= j #>;
|
||||||
|
bool hasCurrent<#= j #>;
|
||||||
|
bool running<#= j #>;
|
||||||
|
T<#= j #> current<#= j #>;
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
int completedCount;
|
||||||
|
bool syncRunning;
|
||||||
|
TResult result;
|
||||||
|
|
||||||
|
public _CombineLatest(<#= paramArgs(i) #>, Func<<#= typeArgs(i) #>> resultSelector, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
this.source<#= j #> = source<#= j #>;
|
||||||
|
<# } #>
|
||||||
|
this.resultSelector = resultSelector;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult Current => result;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
if (completedCount == CompleteCount) return CompletedTasks.False;
|
||||||
|
|
||||||
|
if (enumerator1 == null)
|
||||||
|
{
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
enumerator<#= j #> = source<#= j #>.GetAsyncEnumerator(cancellationToken);
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
|
||||||
|
completionSource.Reset();
|
||||||
|
|
||||||
|
AGAIN:
|
||||||
|
syncRunning = true;
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
if (!running<#= j #>)
|
||||||
|
{
|
||||||
|
running<#= j #> = true;
|
||||||
|
awaiter<#= j #> = enumerator<#= j #>.MoveNextAsync().GetAwaiter();
|
||||||
|
if (awaiter<#= j #>.IsCompleted)
|
||||||
|
{
|
||||||
|
Completed<#= j #>(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
awaiter<#= j #>.SourceOnCompleted(Completed<#= j #>Delegate, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<# } #>
|
||||||
|
|
||||||
|
if (<#= string.Join(" || ", Enumerable.Range(1, i).Select(x => $"!running{x}")) #>)
|
||||||
|
{
|
||||||
|
goto AGAIN;
|
||||||
|
}
|
||||||
|
syncRunning = false;
|
||||||
|
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
static void Completed<#= j #>(object state)
|
||||||
|
{
|
||||||
|
var self = (_CombineLatest)state;
|
||||||
|
self.running<#= j #> = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (self.awaiter<#= j #>.GetResult())
|
||||||
|
{
|
||||||
|
self.hasCurrent<#= j #> = true;
|
||||||
|
self.current<#= j #> = self.enumerator<#= j #>.Current;
|
||||||
|
goto SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.running<#= j #> = true; // as complete, no more call MoveNextAsync.
|
||||||
|
if (Interlocked.Increment(ref self.completedCount) == CompleteCount)
|
||||||
|
{
|
||||||
|
goto COMPLETE;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
self.running<#= j #> = true; // as complete, no more call MoveNextAsync.
|
||||||
|
self.completedCount = CompleteCount;
|
||||||
|
self.completionSource.TrySetException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SUCCESS:
|
||||||
|
if (!self.TrySetResult())
|
||||||
|
{
|
||||||
|
if (self.syncRunning) return;
|
||||||
|
self.running<#= j #> = true; // as complete, no more call MoveNextAsync.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
self.awaiter<#= j #> = self.enumerator<#= j #>.MoveNextAsync().GetAwaiter();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
self.completedCount = CompleteCount;
|
||||||
|
self.completionSource.TrySetException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.awaiter<#= j #>.SourceOnCompleted(Completed<#= j #>Delegate, self);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
COMPLETE:
|
||||||
|
self.completionSource.TrySetResult(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
bool TrySetResult()
|
||||||
|
{
|
||||||
|
if (<#= string.Join(" && ", Enumerable.Range(1, i).Select(x => $"hasCurrent{x}")) #>)
|
||||||
|
{
|
||||||
|
result = resultSelector(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => $"current{x}")) #>);
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
<# for(var j = 1; j <= i; j++) { #>
|
||||||
|
if (enumerator<#= j #> != null)
|
||||||
|
{
|
||||||
|
await enumerator<#= j #>.DisposeAsync();
|
||||||
|
}
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<# } #>
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b1b8cfa9d17af814a971ee2224aaaaa2
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
128
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Pairwise.cs
Normal file
128
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Pairwise.cs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Linq
|
||||||
|
{
|
||||||
|
public static partial class UniTaskAsyncEnumerable
|
||||||
|
{
|
||||||
|
public static IUniTaskAsyncEnumerable<(TSource, TSource)> Pairwise<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
|
||||||
|
return new Pairwise<TSource>(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class Pairwise<TSource> : IUniTaskAsyncEnumerable<(TSource, TSource)>
|
||||||
|
{
|
||||||
|
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||||
|
|
||||||
|
public Pairwise(IUniTaskAsyncEnumerable<TSource> source)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<(TSource, TSource)> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new _Pairwise(source, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class _Pairwise : MoveNextSource, IUniTaskAsyncEnumerator<(TSource, TSource)>
|
||||||
|
{
|
||||||
|
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||||
|
|
||||||
|
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||||
|
UniTask<bool>.Awaiter awaiter;
|
||||||
|
|
||||||
|
TSource prev;
|
||||||
|
bool isFirst;
|
||||||
|
|
||||||
|
public _Pairwise(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (TSource, TSource) Current { get; private set; }
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (enumerator == null)
|
||||||
|
{
|
||||||
|
isFirst = true;
|
||||||
|
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
completionSource.Reset();
|
||||||
|
SourceMoveNext();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceMoveNext()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||||
|
if (awaiter.IsCompleted)
|
||||||
|
{
|
||||||
|
MoveNextCore(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
completionSource.TrySetException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MoveNextCore(object state)
|
||||||
|
{
|
||||||
|
var self = (_Pairwise)state;
|
||||||
|
|
||||||
|
if (self.TryGetResult(self.awaiter, out var result))
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if (self.isFirst)
|
||||||
|
{
|
||||||
|
self.isFirst = false;
|
||||||
|
self.prev = self.enumerator.Current;
|
||||||
|
self.SourceMoveNext(); // run again. okay to use recursive(only one more).
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var p = self.prev;
|
||||||
|
self.prev = self.enumerator.Current;
|
||||||
|
self.Current = (p, self.prev);
|
||||||
|
self.completionSource.TrySetResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.completionSource.TrySetResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
if (enumerator != null)
|
||||||
|
{
|
||||||
|
return enumerator.DisposeAsync();
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cddbf051d2a88f549986c468b23214af
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using Cysharp.Threading.Tasks.Internal;
|
using System.Threading;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Linq
|
namespace Cysharp.Threading.Tasks.Linq
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,241 @@
|
|||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Linq
|
||||||
|
{
|
||||||
|
public static partial class UniTaskAsyncEnumerable
|
||||||
|
{
|
||||||
|
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null)
|
||||||
|
where TTarget : class
|
||||||
|
{
|
||||||
|
var unityObject = target as UnityEngine.Object;
|
||||||
|
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
|
||||||
|
|
||||||
|
if (isUnityObject)
|
||||||
|
{
|
||||||
|
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class EveryValueChangedUnityObject<TTarget, TProperty> : IUniTaskAsyncEnumerable<TProperty>
|
||||||
|
{
|
||||||
|
readonly TTarget target;
|
||||||
|
readonly Func<TTarget, TProperty> propertySelector;
|
||||||
|
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||||
|
readonly PlayerLoopTiming monitorTiming;
|
||||||
|
|
||||||
|
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
|
||||||
|
{
|
||||||
|
this.target = target;
|
||||||
|
this.propertySelector = propertySelector;
|
||||||
|
this.equalityComparer = equalityComparer;
|
||||||
|
this.monitorTiming = monitorTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
|
||||||
|
{
|
||||||
|
readonly TTarget target;
|
||||||
|
readonly UnityEngine.Object targetAsUnityObject;
|
||||||
|
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||||
|
readonly Func<TTarget, TProperty> propertySelector;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
bool first;
|
||||||
|
TProperty currentValue;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
|
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.target = target;
|
||||||
|
this.targetAsUnityObject = target as UnityEngine.Object;
|
||||||
|
this.propertySelector = propertySelector;
|
||||||
|
this.equalityComparer = equalityComparer;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
this.first = true;
|
||||||
|
TaskTracker.TrackActiveTask(this, 2);
|
||||||
|
PlayerLoopHelper.AddAction(monitorTiming, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TProperty Current => currentValue;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
// return false instead of throw
|
||||||
|
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
if (targetAsUnityObject == null)
|
||||||
|
{
|
||||||
|
return CompletedTasks.False;
|
||||||
|
}
|
||||||
|
this.currentValue = propertySelector(target);
|
||||||
|
return CompletedTasks.True;
|
||||||
|
}
|
||||||
|
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
disposed = true;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (disposed || cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
|
||||||
|
{
|
||||||
|
completionSource.TrySetResult(false);
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TProperty nextValue = default(TProperty);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nextValue = propertySelector(target);
|
||||||
|
if (equalityComparer.Equals(currentValue, nextValue))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
completionSource.TrySetException(ex);
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentValue = nextValue;
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class EveryValueChangedStandardObject<TTarget, TProperty> : IUniTaskAsyncEnumerable<TProperty>
|
||||||
|
where TTarget : class
|
||||||
|
{
|
||||||
|
readonly WeakReference<TTarget> target;
|
||||||
|
readonly Func<TTarget, TProperty> propertySelector;
|
||||||
|
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||||
|
readonly PlayerLoopTiming monitorTiming;
|
||||||
|
|
||||||
|
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
|
||||||
|
{
|
||||||
|
this.target = new WeakReference<TTarget>(target, false);
|
||||||
|
this.propertySelector = propertySelector;
|
||||||
|
this.equalityComparer = equalityComparer;
|
||||||
|
this.monitorTiming = monitorTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
|
||||||
|
{
|
||||||
|
readonly WeakReference<TTarget> target;
|
||||||
|
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||||
|
readonly Func<TTarget, TProperty> propertySelector;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
bool first;
|
||||||
|
TProperty currentValue;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
|
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.target = target;
|
||||||
|
this.propertySelector = propertySelector;
|
||||||
|
this.equalityComparer = equalityComparer;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
this.first = true;
|
||||||
|
TaskTracker.TrackActiveTask(this, 2);
|
||||||
|
PlayerLoopHelper.AddAction(monitorTiming, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TProperty Current => currentValue;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
if (!target.TryGetTarget(out var t))
|
||||||
|
{
|
||||||
|
return CompletedTasks.False;
|
||||||
|
}
|
||||||
|
this.currentValue = propertySelector(t);
|
||||||
|
return CompletedTasks.True;
|
||||||
|
}
|
||||||
|
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
disposed = true;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("TRY_RESULT:" + target.TryGetTarget(out var _));
|
||||||
|
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
||||||
|
{
|
||||||
|
completionSource.TrySetResult(false);
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TProperty nextValue = default(TProperty);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nextValue = propertySelector(t);
|
||||||
|
if (equalityComparer.Equals(currentValue, nextValue))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
completionSource.TrySetException(ex);
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentValue = nextValue;
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1ec39f1c41c305344854782c935ad354
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -200,27 +200,43 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
static void InitOnEditor()
|
static void InitOnEditor()
|
||||||
{
|
{
|
||||||
//Execute the play mode init method
|
// Execute the play mode init method
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
//register an Editor update delegate, used to forcing playerLoop update
|
// register an Editor update delegate, used to forcing playerLoop update
|
||||||
EditorApplication.update += ForceEditorPlayerLoopUpdate;
|
EditorApplication.update += ForceEditorPlayerLoopUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ForceEditorPlayerLoopUpdate()
|
private static void ForceEditorPlayerLoopUpdate()
|
||||||
{
|
{
|
||||||
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling ||
|
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||||
EditorApplication.isUpdating)
|
|
||||||
{
|
{
|
||||||
// Not in Edit mode, don't interfere
|
// Not in Edit mode, don't interfere
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//force unity to update PlayerLoop callbacks
|
// EditorApplication.QueuePlayerLoopUpdate causes performance issue, don't call directly.
|
||||||
EditorApplication.QueuePlayerLoopUpdate();
|
// EditorApplication.QueuePlayerLoopUpdate();
|
||||||
|
|
||||||
|
if (yielders != null)
|
||||||
|
{
|
||||||
|
foreach (var item in yielders)
|
||||||
|
{
|
||||||
|
if (item != null) item.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runners != null)
|
||||||
|
{
|
||||||
|
foreach (var item in runners)
|
||||||
|
{
|
||||||
|
if (item != null) item.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -56,9 +56,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
|
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<YieldPromise> pool = new PromisePool<YieldPromise>();
|
static TaskPool<YieldPromise> pool;
|
||||||
|
public YieldPromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static YieldPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
@@ -74,7 +80,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new YieldPromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new YieldPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
@@ -90,12 +100,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,24 +135,32 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~YieldPromise()
|
~YieldPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<DelayFramePromise> pool = new PromisePool<DelayFramePromise>();
|
static TaskPool<DelayFramePromise> pool;
|
||||||
|
public DelayFramePromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static DelayFramePromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
int delayFrameCount;
|
int delayFrameCount;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
@@ -162,7 +179,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new DelayFramePromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new DelayFramePromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.delayFrameCount = delayFrameCount;
|
result.delayFrameCount = delayFrameCount;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
@@ -179,12 +199,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,26 +240,34 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
currentFrameCount = default;
|
currentFrameCount = default;
|
||||||
delayFrameCount = default;
|
delayFrameCount = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~DelayFramePromise()
|
~DelayFramePromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<DelayPromise> pool = new PromisePool<DelayPromise>();
|
static TaskPool<DelayPromise> pool;
|
||||||
|
public DelayPromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static DelayPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
float delayFrameTimeSpan;
|
float delayFrameTimeSpan;
|
||||||
float elapsed;
|
float elapsed;
|
||||||
@@ -259,7 +286,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new DelayPromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new DelayPromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.elapsed = 0.0f;
|
result.elapsed = 0.0f;
|
||||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||||
@@ -277,12 +307,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,26 +348,34 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
delayFrameTimeSpan = default;
|
delayFrameTimeSpan = default;
|
||||||
elapsed = default;
|
elapsed = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~DelayPromise()
|
~DelayPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<DelayIgnoreTimeScalePromise> pool = new PromisePool<DelayIgnoreTimeScalePromise>();
|
static TaskPool<DelayIgnoreTimeScalePromise> pool;
|
||||||
|
public DelayIgnoreTimeScalePromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static DelayIgnoreTimeScalePromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayIgnoreTimeScalePromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
float delayFrameTimeSpan;
|
float delayFrameTimeSpan;
|
||||||
float elapsed;
|
float elapsed;
|
||||||
@@ -357,7 +394,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new DelayIgnoreTimeScalePromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new DelayIgnoreTimeScalePromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.elapsed = 0.0f;
|
result.elapsed = 0.0f;
|
||||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||||
@@ -375,12 +415,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,17 +456,19 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
delayFrameTimeSpan = default;
|
delayFrameTimeSpan = default;
|
||||||
elapsed = default;
|
elapsed = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~DelayIgnoreTimeScalePromise()
|
~DelayIgnoreTimeScalePromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,34 +105,67 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// helper of create add UniTaskVoid to delegate.
|
/// helper of create add UniTaskVoid to delegate.
|
||||||
/// For example: FooEvent += () => UniTask.Void(async () => { /* */ })
|
/// For example: FooEvent += () => UniTask.Void(async () => { /* */ })
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Void(Func<UniTask> asyncAction)
|
public static void Void(Func<UniTaskVoid> asyncAction)
|
||||||
{
|
{
|
||||||
asyncAction().Forget();
|
asyncAction().Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Action VoidAction(Func<UniTask> asyncAction)
|
/// <summary>
|
||||||
|
/// helper of create add UniTaskVoid to delegate.
|
||||||
|
/// </summary>
|
||||||
|
public static void Void(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return () => Void(asyncAction);
|
asyncAction(cancellationToken).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
|
|
||||||
public static UnityEngine.Events.UnityAction VoidUnityAction(Func<UniTask> asyncAction)
|
|
||||||
{
|
|
||||||
return () => Void(asyncAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// helper of create add UniTaskVoid to delegate.
|
/// helper of create add UniTaskVoid to delegate.
|
||||||
/// For example: FooEvent += (sender, e) => UniTask.Void(async arg => { /* */ }, (sender, e))
|
/// For example: FooEvent += (sender, e) => UniTask.Void(async arg => { /* */ }, (sender, e))
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Void<T>(Func<T, UniTask> asyncAction, T state)
|
public static void Void<T>(Func<T, UniTaskVoid> asyncAction, T state)
|
||||||
{
|
{
|
||||||
asyncAction(state).Forget();
|
asyncAction(state).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// helper of create add UniTaskVoid to delegate.
|
||||||
|
/// For example: FooAction = UniTask.Action(async () => { /* */ })
|
||||||
|
/// </summary>
|
||||||
|
public static Action Action(Func<UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return () => asyncAction().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// helper of create add UniTaskVoid to delegate.
|
||||||
|
/// </summary>
|
||||||
|
public static Action Action(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return () => asyncAction(cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For exampe: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction UnityAction(Func<UniTaskVoid> asyncAction)
|
||||||
|
{
|
||||||
|
return () => asyncAction().Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
|
/// For exampe: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
|
||||||
|
/// </summary>
|
||||||
|
public static UnityEngine.Events.UnityAction UnityAction(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return () => asyncAction(cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defer the task creation just before call await.
|
/// Defer the task creation just before call await.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -28,16 +28,22 @@ namespace Cysharp.Threading.Tasks
|
|||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
var unityObject = target as UnityEngine.Object;
|
var unityObject = target as UnityEngine.Object;
|
||||||
var isUnityObject = !object.ReferenceEquals(target, null); // don't use (unityObject == null)
|
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
|
||||||
|
|
||||||
return new UniTask<U>(isUnityObject
|
return new UniTask<U>(isUnityObject
|
||||||
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token)
|
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token)
|
||||||
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
|
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<WaitUntilPromise> pool = new PromisePool<WaitUntilPromise>();
|
static TaskPool<WaitUntilPromise> pool;
|
||||||
|
public WaitUntilPromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static WaitUntilPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilPromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
Func<bool> predicate;
|
Func<bool> predicate;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
@@ -55,7 +61,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new WaitUntilPromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitUntilPromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.predicate = predicate;
|
result.predicate = predicate;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
@@ -72,12 +81,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,25 +129,33 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
predicate = default;
|
predicate = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaitUntilPromise()
|
~WaitUntilPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<WaitWhilePromise> pool = new PromisePool<WaitWhilePromise>();
|
static TaskPool<WaitWhilePromise> pool;
|
||||||
|
public WaitWhilePromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static WaitWhilePromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
Func<bool> predicate;
|
Func<bool> predicate;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
@@ -157,7 +173,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new WaitWhilePromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitWhilePromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.predicate = predicate;
|
result.predicate = predicate;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
@@ -174,12 +193,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,25 +241,33 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
predicate = default;
|
predicate = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaitWhilePromise()
|
~WaitWhilePromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<WaitUntilCanceledPromise> pool = new PromisePool<WaitUntilCanceledPromise>();
|
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||||
|
public WaitUntilCanceledPromise NextNode { get; set; }
|
||||||
|
|
||||||
|
static WaitUntilCanceledPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
@@ -258,7 +284,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new WaitUntilCanceledPromise();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitUntilCanceledPromise();
|
||||||
|
}
|
||||||
|
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
@@ -274,12 +303,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,15 +337,17 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaitUntilCanceledPromise()
|
~WaitUntilCanceledPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
@@ -325,11 +355,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
// where T : UnityEngine.Object, can not add constraint
|
// where T : UnityEngine.Object, can not add constraint
|
||||||
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, IPromisePoolItem
|
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedUnityObjectPromise<T, U>>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool = new PromisePool<WaitUntilValueChangedUnityObjectPromise<T, U>>();
|
static TaskPool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool;
|
||||||
|
public WaitUntilValueChangedUnityObjectPromise<T, U> NextNode { get; set; }
|
||||||
|
|
||||||
|
static WaitUntilValueChangedUnityObjectPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilValueChangedUnityObjectPromise<T, U>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
T target;
|
T target;
|
||||||
|
UnityEngine.Object targetAsUnityObject;
|
||||||
U currentValue;
|
U currentValue;
|
||||||
Func<T, U> monitorFunction;
|
Func<T, U> monitorFunction;
|
||||||
IEqualityComparer<U> equalityComparer;
|
IEqualityComparer<U> equalityComparer;
|
||||||
@@ -348,9 +385,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new WaitUntilValueChangedUnityObjectPromise<T, U>();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitUntilValueChangedUnityObjectPromise<T, U>();
|
||||||
|
}
|
||||||
|
|
||||||
result.target = target;
|
result.target = target;
|
||||||
|
result.targetAsUnityObject = target as UnityEngine.Object;
|
||||||
result.monitorFunction = monitorFunction;
|
result.monitorFunction = monitorFunction;
|
||||||
result.currentValue = monitorFunction(target);
|
result.currentValue = monitorFunction(target);
|
||||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||||
@@ -368,12 +409,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +439,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested || target == null) // destroyed = cancel.
|
if (cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
|
||||||
{
|
{
|
||||||
core.TrySetCanceled(cancellationToken);
|
core.TrySetCanceled(cancellationToken);
|
||||||
return false;
|
return false;
|
||||||
@@ -424,29 +464,37 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
target = default;
|
target = default;
|
||||||
currentValue = default;
|
currentValue = default;
|
||||||
monitorFunction = default;
|
monitorFunction = default;
|
||||||
equalityComparer = default;
|
equalityComparer = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaitUntilValueChangedUnityObjectPromise()
|
~WaitUntilValueChangedUnityObjectPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class WaitUntilValueChangedStandardObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, IPromisePoolItem
|
sealed class WaitUntilValueChangedStandardObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedStandardObjectPromise<T, U>>
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
static readonly PromisePool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool = new PromisePool<WaitUntilValueChangedStandardObjectPromise<T, U>>();
|
static TaskPool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool;
|
||||||
|
public WaitUntilValueChangedStandardObjectPromise<T, U> NextNode { get; set; }
|
||||||
|
|
||||||
|
static WaitUntilValueChangedStandardObjectPromise()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilValueChangedStandardObjectPromise<T, U>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
WeakReference<T> target;
|
WeakReference<T> target;
|
||||||
U currentValue;
|
U currentValue;
|
||||||
@@ -467,7 +515,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new WaitUntilValueChangedStandardObjectPromise<T, U>();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new WaitUntilValueChangedStandardObjectPromise<T, U>();
|
||||||
|
}
|
||||||
|
|
||||||
result.target = new WeakReference<T>(target, false); // wrap in WeakReference.
|
result.target = new WeakReference<T>(target, false); // wrap in WeakReference.
|
||||||
result.monitorFunction = monitorFunction;
|
result.monitorFunction = monitorFunction;
|
||||||
@@ -487,12 +538,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,19 +593,21 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
target = default;
|
target = default;
|
||||||
currentValue = default;
|
currentValue = default;
|
||||||
monitorFunction = default;
|
monitorFunction = default;
|
||||||
equalityComparer = default;
|
equalityComparer = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaitUntilValueChangedStandardObjectPromise()
|
~WaitUntilValueChangedStandardObjectPromise()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
"name": "UniTask",
|
"name": "UniTask",
|
||||||
"references": [
|
"references": [
|
||||||
"Unity.ResourceManager",
|
"Unity.ResourceManager",
|
||||||
"Unity.TextMeshPro"
|
"Unity.TextMeshPro",
|
||||||
|
"DOTween.Modules"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
@@ -21,6 +22,11 @@
|
|||||||
"name": "com.unity.textmeshpro",
|
"name": "com.unity.textmeshpro",
|
||||||
"expression": "",
|
"expression": "",
|
||||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "com.demigiant.dotween",
|
||||||
|
"expression": "",
|
||||||
|
"define": "UNITASK_DOTWEEN_SUPPORT"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#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
|
||||||
#pragma warning disable CS0436
|
#pragma warning disable CS0436
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks.CompilerServices;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
using Cysharp.Threading.Tasks.CompilerServices;
|
using System.Runtime.InteropServices;
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
internal static class AwaiterActions
|
internal static class AwaiterActions
|
||||||
{
|
{
|
||||||
internal static readonly Action<object> InvokeActionDelegate = InvokeAction;
|
internal static readonly Action<object> InvokeContinuationDelegate = Continuation;
|
||||||
|
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
static void InvokeAction(object state)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
static void Continuation(object state)
|
||||||
{
|
{
|
||||||
((Action)state).Invoke();
|
((Action)state).Invoke();
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// Lightweight unity specified task-like object.
|
/// Lightweight unity specified task-like object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
|
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public readonly partial struct UniTask
|
public readonly partial struct UniTask
|
||||||
{
|
{
|
||||||
readonly IUniTaskSource source;
|
readonly IUniTaskSource source;
|
||||||
@@ -68,6 +69,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask<bool>(new IsCanceledSource(source), token);
|
return new UniTask<bool>(new IsCanceledSource(source), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
|
||||||
|
{
|
||||||
|
if (self.source == null)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new System.Threading.Tasks.ValueTask(self.source, self.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
if (source == null) return "()";
|
if (source == null) return "()";
|
||||||
@@ -298,7 +313,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
task.source.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +327,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
task.source.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +354,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// Lightweight unity specified task-like object.
|
/// Lightweight unity specified task-like object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder<>))]
|
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder<>))]
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public readonly struct UniTask<T>
|
public readonly struct UniTask<T>
|
||||||
{
|
{
|
||||||
readonly IUniTaskSource<T> source;
|
readonly IUniTaskSource<T> source;
|
||||||
@@ -414,6 +430,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return self.AsUniTask();
|
return self.AsUniTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
|
||||||
|
{
|
||||||
|
if (self.source == null)
|
||||||
|
{
|
||||||
|
return new System.Threading.Tasks.ValueTask<T>(self.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
|
/// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -621,7 +651,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +666,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,14 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
// setup result
|
// setup result
|
||||||
this.hasUnhandledError = true;
|
this.hasUnhandledError = true;
|
||||||
this.error = ExceptionDispatchInfo.Capture(error);
|
if (error is OperationCanceledException)
|
||||||
|
{
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.error = ExceptionDispatchInfo.Capture(error);
|
||||||
|
}
|
||||||
|
|
||||||
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
|
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
|
||||||
{
|
{
|
||||||
@@ -264,7 +271,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (token != version)
|
if (token != version)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("token version is not matched, can not await twice.");
|
throw new InvalidOperationException("Token version is not matched, can not await twice or get Status after await.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,9 +375,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AutoResetUniTaskCompletionSource : IUniTaskSource, IPromisePoolItem, IPromise
|
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AutoResetUniTaskCompletionSource> pool = new PromisePool<AutoResetUniTaskCompletionSource>();
|
static TaskPool<AutoResetUniTaskCompletionSource> pool;
|
||||||
|
public AutoResetUniTaskCompletionSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AutoResetUniTaskCompletionSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AutoResetUniTaskCompletionSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
@@ -381,9 +394,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public static AutoResetUniTaskCompletionSource Create()
|
public static AutoResetUniTaskCompletionSource Create()
|
||||||
{
|
{
|
||||||
var value = pool.TryRent() ?? new AutoResetUniTaskCompletionSource();
|
if (!pool.TryPop(out var result))
|
||||||
TaskTracker.TrackActiveTask(value, 2);
|
{
|
||||||
return value;
|
result = new AutoResetUniTaskCompletionSource();
|
||||||
|
}
|
||||||
|
TaskTracker.TrackActiveTask(result, 2);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
@@ -445,12 +461,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -474,14 +489,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
void IPromisePoolItem.Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoResetUniTaskCompletionSource()
|
~AutoResetUniTaskCompletionSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
return;
|
return;
|
||||||
@@ -584,9 +601,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, IPromisePoolItem, IPromise<T>
|
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AutoResetUniTaskCompletionSource<T>> pool = new PromisePool<AutoResetUniTaskCompletionSource<T>>();
|
static TaskPool<AutoResetUniTaskCompletionSource<T>> pool;
|
||||||
|
public AutoResetUniTaskCompletionSource<T> NextNode { get; set; }
|
||||||
|
|
||||||
|
static AutoResetUniTaskCompletionSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AutoResetUniTaskCompletionSource<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
UniTaskCompletionSourceCore<T> core;
|
||||||
|
|
||||||
@@ -597,7 +620,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
public static AutoResetUniTaskCompletionSource<T> Create()
|
public static AutoResetUniTaskCompletionSource<T> Create()
|
||||||
{
|
{
|
||||||
var result = pool.TryRent() ?? new AutoResetUniTaskCompletionSource<T>();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AutoResetUniTaskCompletionSource<T>();
|
||||||
|
}
|
||||||
TaskTracker.TrackActiveTask(result, 2);
|
TaskTracker.TrackActiveTask(result, 2);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -661,12 +687,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,14 +720,17 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DebuggerHidden]
|
[DebuggerHidden]
|
||||||
void IPromisePoolItem.Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
~AutoResetUniTaskCompletionSource()
|
~AutoResetUniTaskCompletionSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -559,36 +559,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return await continuationFunction();
|
return await continuationFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
|
|
||||||
public static async UniTask ConfigureAwait(this Task task, PlayerLoopTiming timing)
|
|
||||||
{
|
|
||||||
await task.ConfigureAwait(false);
|
|
||||||
await UniTask.Yield(timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async UniTask<T> ConfigureAwait<T>(this Task<T> task, PlayerLoopTiming timing)
|
|
||||||
{
|
|
||||||
var v = await task.ConfigureAwait(false);
|
|
||||||
await UniTask.Yield(timing);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async UniTask ConfigureAwait(this UniTask task, PlayerLoopTiming timing)
|
|
||||||
{
|
|
||||||
await task;
|
|
||||||
await UniTask.Yield(timing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async UniTask<T> ConfigureAwait<T>(this UniTask<T> task, PlayerLoopTiming timing)
|
|
||||||
{
|
|
||||||
var v = await task;
|
|
||||||
await UniTask.Yield(timing);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public static async UniTask<T> Unwrap<T>(this UniTask<UniTask<T>> task)
|
public static async UniTask<T> Unwrap<T>(this UniTask<UniTask<T>> task)
|
||||||
{
|
{
|
||||||
return await await task;
|
return await await task;
|
||||||
@@ -601,7 +571,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
class ToCoroutineEnumerator : IEnumerator
|
sealed class ToCoroutineEnumerator : IEnumerator
|
||||||
{
|
{
|
||||||
bool completed;
|
bool completed;
|
||||||
UniTask task;
|
UniTask task;
|
||||||
@@ -659,12 +629,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return !completed;
|
return !completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
void IEnumerator.Reset()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToCoroutineEnumerator<T> : IEnumerator
|
sealed class ToCoroutineEnumerator<T> : IEnumerator
|
||||||
{
|
{
|
||||||
bool completed;
|
bool completed;
|
||||||
Action<T> resultHandler = null;
|
Action<T> resultHandler = null;
|
||||||
@@ -730,7 +700,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return !completed;
|
return !completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
void IEnumerator.Reset()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static class UniTaskObservableExtensions
|
public static class UniTaskObservableExtensions
|
||||||
{
|
{
|
||||||
public static UniTask<T> ToUniTask<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken), bool useFirstValue = false)
|
public static UniTask<T> ToUniTask<T>(this IObservable<T> source, bool useFirstValue = false, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var promise = new UniTaskCompletionSource<T>();
|
var promise = new UniTaskCompletionSource<T>();
|
||||||
var disposable = new SingleAssignmentDisposable();
|
var disposable = new SingleAssignmentDisposable();
|
||||||
|
|||||||
@@ -9,41 +9,11 @@ using Cysharp.Threading.Tasks.CompilerServices;
|
|||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
[AsyncMethodBuilder(typeof(AsyncUniTaskVoidMethodBuilder))]
|
[AsyncMethodBuilder(typeof(AsyncUniTaskVoidMethodBuilder))]
|
||||||
public struct UniTaskVoid
|
public readonly struct UniTaskVoid
|
||||||
{
|
{
|
||||||
public void Forget()
|
public void Forget()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public Awaiter GetAwaiter()
|
|
||||||
{
|
|
||||||
return new Awaiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct Awaiter : ICriticalNotifyCompletion
|
|
||||||
{
|
|
||||||
[DebuggerHidden]
|
|
||||||
public bool IsCompleted => true;
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void GetResult()
|
|
||||||
{
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
UnityEngine.Debug.LogWarning("UniTaskVoid can't await, always fire-and-forget. use Forget instead of await.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void OnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerHidden]
|
|
||||||
public void UnsafeOnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static partial class UnityAsyncExtensions
|
public static partial class UnityAsyncExtensions
|
||||||
{
|
{
|
||||||
public static async UniTask WaitAsync(this JobHandle jobHandle, PlayerLoopTiming waitTiming)
|
public static async UniTask WaitAsync(this JobHandle jobHandle, PlayerLoopTiming waitTiming, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
await UniTask.Yield(waitTiming);
|
await UniTask.Yield(waitTiming);
|
||||||
jobHandle.Complete();
|
jobHandle.Complete();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested(); // call cancel after Complete.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask.Awaiter GetAwaiter(this JobHandle jobHandle)
|
public static UniTask.Awaiter GetAwaiter(this JobHandle jobHandle)
|
||||||
@@ -29,21 +30,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask(handler, token).GetAwaiter();
|
return new UniTask(handler, token).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this JobHandle jobHandle)
|
// can not pass CancellationToken because can't handle JobHandle's Complete and NativeArray.Dispose.
|
||||||
{
|
|
||||||
var handler = JobHandlePromise.Create(jobHandle, out var token);
|
|
||||||
{
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.EarlyUpdate, handler);
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.PreUpdate, handler);
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, handler);
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.PreLateUpdate, handler);
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.PostLateUpdate, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UniTask(handler, token);
|
public static UniTask ToUniTask(this JobHandle jobHandle, PlayerLoopTiming waitTiming)
|
||||||
}
|
|
||||||
|
|
||||||
public static UniTask ConfigureAwait(this JobHandle jobHandle, PlayerLoopTiming waitTiming)
|
|
||||||
{
|
{
|
||||||
var handler = JobHandlePromise.Create(jobHandle, out var token);
|
var handler = JobHandlePromise.Create(jobHandle, out var token);
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static partial class UnityAsyncExtensions
|
public static partial class UnityAsyncExtensions
|
||||||
{
|
{
|
||||||
#region AsyncOperation
|
#region AsyncOperation
|
||||||
|
|
||||||
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
|
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new AsyncOperationAwaiter(asyncOperation);
|
return new AsyncOperationAwaiter(asyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this AsyncOperation asyncOperation)
|
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||||
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ConfigureAwait(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||||
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
|
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
|
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -70,14 +70,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
asyncOperation.completed += continuationAction;
|
asyncOperation.completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AsyncOperationConfiguredSource> pool = new PromisePool<AsyncOperationConfiguredSource>();
|
static TaskPool<AsyncOperationConfiguredSource> pool;
|
||||||
|
public AsyncOperationConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AsyncOperationConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
AsyncOperation asyncOperation;
|
AsyncOperation asyncOperation;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -97,7 +103,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new AsyncOperationConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AsyncOperationConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -115,17 +124,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
{
|
{
|
||||||
return core.GetStatus(token);
|
return core.GetStatus(token);
|
||||||
@@ -163,26 +170,28 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AsyncOperationConfiguredSource()
|
~AsyncOperationConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# endregion
|
#endregion
|
||||||
|
|
||||||
#region ResourceRequest
|
#region ResourceRequest
|
||||||
|
|
||||||
public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation)
|
public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation)
|
||||||
{
|
{
|
||||||
@@ -190,18 +199,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new ResourceRequestAwaiter(asyncOperation);
|
return new ResourceRequestAwaiter(asyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation)
|
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityEngine.Object> ConfigureAwait(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
|
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
|
public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -243,14 +252,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
asyncOperation.completed += continuationAction;
|
asyncOperation.completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, IPromisePoolItem
|
class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<ResourceRequestConfiguredSource> pool = new PromisePool<ResourceRequestConfiguredSource>();
|
static TaskPool<ResourceRequestConfiguredSource> pool;
|
||||||
|
public ResourceRequestConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static ResourceRequestConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(ResourceRequestConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
ResourceRequest asyncOperation;
|
ResourceRequest asyncOperation;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -270,7 +285,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new ResourceRequestConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new ResourceRequestConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -288,13 +306,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,26 +357,28 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ResourceRequestConfiguredSource()
|
~ResourceRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# endregion
|
#endregion
|
||||||
|
|
||||||
#region AssetBundleRequest
|
#region AssetBundleRequest
|
||||||
|
|
||||||
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
||||||
{
|
{
|
||||||
@@ -367,18 +386,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new AssetBundleRequestAwaiter(asyncOperation);
|
return new AssetBundleRequestAwaiter(asyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation)
|
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityEngine.Object> ConfigureAwait(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
|
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
|
public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -420,14 +439,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
asyncOperation.completed += continuationAction;
|
asyncOperation.completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, IPromisePoolItem
|
class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AssetBundleRequestConfiguredSource> pool = new PromisePool<AssetBundleRequestConfiguredSource>();
|
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
||||||
|
public AssetBundleRequestConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AssetBundleRequestConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AssetBundleRequestConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
AssetBundleRequest asyncOperation;
|
AssetBundleRequest asyncOperation;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -447,7 +472,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new AssetBundleRequestConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AssetBundleRequestConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -465,13 +493,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,26 +543,28 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
core.Reset();
|
core.Reset();
|
||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AssetBundleRequestConfiguredSource()
|
~AssetBundleRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# endregion
|
#endregion
|
||||||
|
|
||||||
#region AssetBundleCreateRequest
|
#region AssetBundleCreateRequest
|
||||||
|
|
||||||
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
||||||
{
|
{
|
||||||
@@ -544,18 +572,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new AssetBundleCreateRequestAwaiter(asyncOperation);
|
return new AssetBundleCreateRequestAwaiter(asyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation)
|
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<AssetBundle> ConfigureAwait(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
|
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
|
public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -597,14 +625,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
asyncOperation.completed += continuationAction;
|
asyncOperation.completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, IPromisePoolItem
|
class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<AssetBundleCreateRequestConfiguredSource> pool = new PromisePool<AssetBundleCreateRequestConfiguredSource>();
|
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
||||||
|
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AssetBundleCreateRequestConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(AssetBundleCreateRequestConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
AssetBundleCreateRequest asyncOperation;
|
AssetBundleCreateRequest asyncOperation;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -624,7 +658,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new AssetBundleCreateRequestConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AssetBundleCreateRequestConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -642,13 +679,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,27 +729,29 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
core.Reset();
|
core.Reset();
|
||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AssetBundleCreateRequestConfiguredSource()
|
~AssetBundleCreateRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# endregion
|
#endregion
|
||||||
|
|
||||||
#if ENABLE_UNITYWEBREQUEST
|
#if ENABLE_UNITYWEBREQUEST
|
||||||
#region UnityWebRequestAsyncOperation
|
#region UnityWebRequestAsyncOperation
|
||||||
|
|
||||||
public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
|
public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
|
||||||
{
|
{
|
||||||
@@ -722,18 +759,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UnityWebRequestAsyncOperationAwaiter(asyncOperation);
|
return new UnityWebRequestAsyncOperationAwaiter(asyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation)
|
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest);
|
||||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
|
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<UnityWebRequest> ConfigureAwait(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest);
|
||||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
|
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
|
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -775,14 +812,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public void UnsafeOnCompleted(Action continuation)
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
asyncOperation.completed += continuationAction;
|
asyncOperation.completed += continuationAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, IPromisePoolItem
|
class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
||||||
{
|
{
|
||||||
static readonly PromisePool<UnityWebRequestAsyncOperationConfiguredSource> pool = new PromisePool<UnityWebRequestAsyncOperationConfiguredSource>();
|
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
||||||
|
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static UnityWebRequestAsyncOperationConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPoolMonitor.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
UnityWebRequestAsyncOperation asyncOperation;
|
UnityWebRequestAsyncOperation asyncOperation;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
@@ -802,7 +845,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
|
return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = pool.TryRent() ?? new UnityWebRequestAsyncOperationConfiguredSource();
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new UnityWebRequestAsyncOperationConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
@@ -820,13 +866,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
|
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.TryReturn(this);
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,6 +899,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
asyncOperation.webRequest.Abort();
|
||||||
core.TrySetCanceled(cancellationToken);
|
core.TrySetCanceled(cancellationToken);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -872,24 +918,26 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
core.Reset();
|
core.Reset();
|
||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~UnityWebRequestAsyncOperationConfiguredSource()
|
~UnityWebRequestAsyncOperationConfiguredSource()
|
||||||
{
|
{
|
||||||
if (pool.TryReturn(this))
|
if (TryReturn())
|
||||||
{
|
{
|
||||||
GC.ReRegisterForFinalize(this);
|
GC.ReRegisterForFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# endregion
|
#endregion
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#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 Cysharp.Threading.Tasks.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using Cysharp.Threading.Tasks.Linq;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -27,6 +26,21 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UnityEventHandlerAsyncEnumerable(unityEvent, cancellationToken);
|
return new UnityEventHandlerAsyncEnumerable(unityEvent, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AsyncUnityEventHandler<T> GetAsyncEventHandler<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<T>(unityEvent, cancellationToken, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<T> OnInvokeAsync<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<T>(unityEvent, cancellationToken, true).OnInvokeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskAsyncEnumerable<T> OnInvokeAsAsyncEnumerable<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new UnityEventHandlerAsyncEnumerable<T>(unityEvent, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public static IAsyncClickEventHandler GetAsyncClickEventHandler(this Button button)
|
public static IAsyncClickEventHandler GetAsyncClickEventHandler(this Button button)
|
||||||
{
|
{
|
||||||
return new AsyncUnityEventHandler(button.onClick, button.GetCancellationTokenOnDestroy(), false);
|
return new AsyncUnityEventHandler(button.onClick, button.GetCancellationTokenOnDestroy(), false);
|
||||||
@@ -207,6 +221,36 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
|
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this InputField inputField)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this InputField inputField, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<string> OnValueChangedAsync(this InputField inputField)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<string> OnValueChangedAsync(this InputField inputField, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this InputField inputField)
|
||||||
|
{
|
||||||
|
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this InputField inputField, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public static IAsyncValueChangedEventHandler<int> GetAsyncValueChangedEventHandler(this Dropdown dropdown)
|
public static IAsyncValueChangedEventHandler<int> GetAsyncValueChangedEventHandler(this Dropdown dropdown)
|
||||||
{
|
{
|
||||||
return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, dropdown.GetCancellationTokenOnDestroy(), false);
|
return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, dropdown.GetCancellationTokenOnDestroy(), false);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"version": "2.0.7-rc4",
|
"version": "2.0.12-rc9",
|
||||||
"unity": "2018.3",
|
"unity": "2019.1",
|
||||||
"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" ],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"category": "Task",
|
"category": "Task",
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ using System.Threading.Tasks;
|
|||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using Unity.Jobs;
|
using Unity.Jobs;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
// using DG.Tweening;
|
||||||
|
|
||||||
public struct MyJob : IJob
|
public struct MyJob : IJob
|
||||||
{
|
{
|
||||||
public int loopCount;
|
public int loopCount;
|
||||||
@@ -35,8 +38,33 @@ public enum MyEnum
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SimplePresenter
|
||||||
|
{
|
||||||
|
// View
|
||||||
|
public UnityEngine.UI.InputField Input;
|
||||||
|
|
||||||
|
|
||||||
|
// Presenter
|
||||||
|
|
||||||
|
|
||||||
|
public SimplePresenter()
|
||||||
|
{
|
||||||
|
//Input.OnValueChangedAsAsyncEnumerable()
|
||||||
|
// .Queue()
|
||||||
|
// .SelectAwait(async x =>
|
||||||
|
// {
|
||||||
|
// await UniTask.Delay(TimeSpan.FromSeconds(1));
|
||||||
|
// return x;
|
||||||
|
// })
|
||||||
|
// .Select(x=> x.ToUpper())
|
||||||
|
// .BindTo(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +115,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
{
|
{
|
||||||
public Button okButton;
|
public Button okButton;
|
||||||
public Button cancelButton;
|
public Button cancelButton;
|
||||||
public Text text;
|
|
||||||
|
|
||||||
CancellationTokenSource cts;
|
CancellationTokenSource cts;
|
||||||
|
|
||||||
@@ -110,6 +138,48 @@ public class SandboxMain : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class Model
|
||||||
|
{
|
||||||
|
// State<int> Hp { get; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Model()
|
||||||
|
{
|
||||||
|
// hp = new AsyncReactiveProperty<int>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//setHp = Hp.GetSetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Increment(int value)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// setHp(Hp.Value += value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Text text;
|
||||||
|
public Button button;
|
||||||
|
|
||||||
|
|
||||||
|
void Start2()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async UniTask RunStandardDelayAsync()
|
async UniTask RunStandardDelayAsync()
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.Log("DEB");
|
UnityEngine.Debug.Log("DEB");
|
||||||
@@ -122,19 +192,20 @@ public class SandboxMain : MonoBehaviour
|
|||||||
async UniTask RunJobAsync()
|
async UniTask RunJobAsync()
|
||||||
{
|
{
|
||||||
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
|
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
|
||||||
JobHandle.ScheduleBatchedJobs();
|
try
|
||||||
|
{
|
||||||
|
JobHandle.ScheduleBatchedJobs();
|
||||||
|
|
||||||
var scheduled = job.Schedule();
|
var scheduled = job.Schedule();
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log("OK");
|
||||||
|
await scheduled; // .ConfigureAwait(PlayerLoopTiming.Update); // .WaitAsync(PlayerLoopTiming.Update);
|
||||||
|
UnityEngine.Debug.Log("OK2");
|
||||||
|
}
|
||||||
UnityEngine.Debug.Log("OK");
|
finally
|
||||||
await scheduled; // .ConfigureAwait(PlayerLoopTiming.Update); // .WaitAsync(PlayerLoopTiming.Update);
|
{
|
||||||
UnityEngine.Debug.Log("OK2");
|
job.inOut.Dispose();
|
||||||
|
}
|
||||||
job.inOut.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,38 +241,130 @@ public class SandboxMain : MonoBehaviour
|
|||||||
Debug.Log("Done");
|
Debug.Log("Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start()
|
public int MyProperty { get; set; }
|
||||||
|
|
||||||
|
public class MyClass
|
||||||
{
|
{
|
||||||
//var rp = new AsyncReactiveProperty<int>(10);
|
public int MyProperty { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
//Running(rp).Forget();
|
async Task Test1()
|
||||||
|
{
|
||||||
|
var r = await TcsAsync("https://bing.com/");
|
||||||
|
Debug.Log("TASKASYNC");
|
||||||
|
}
|
||||||
|
|
||||||
//await UniTaskAsyncEnumerable.EveryUpdate().Take(10).ForEachAsync((x, i) => rp.Value = i);
|
async UniTaskVoid Test2()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//var cts = new CancellationTokenSource();
|
||||||
|
//var r = UniAsync("https://bing.com/", cts.Token);
|
||||||
|
//cts.Cancel();
|
||||||
|
//await r;
|
||||||
|
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
||||||
|
Debug.Log("UNIASYNC1 ");
|
||||||
|
|
||||||
//rp.Dispose();
|
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
||||||
|
Debug.Log("UNIASYNC2");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Debug.Log("Canceled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//var channel = Channel.CreateSingleConsumerUnbounded<int>();
|
IEnumerator Test3(string url)
|
||||||
//Debug.Log("wait channel");
|
{
|
||||||
//await channel.Reader.ReadAllAsync(this.GetCancellationTokenOnDestroy()).ForEachAsync(_ => { });
|
var req = UnityWebRequest.Get(url).SendWebRequest();
|
||||||
|
yield return req;
|
||||||
|
Debug.Log("COROUTINE");
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task<UnityWebRequest> TcsAsync(string url)
|
||||||
|
{
|
||||||
|
var req = await UnityWebRequest.Get(url).SendWebRequest();
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTask<UnityWebRequest> UniAsync(string url, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var req = await UnityWebRequest.Get(url).SendWebRequest().WithCancellation(cancellationToken);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var pubsub = new AsyncMessageBroker<int>();
|
async UniTaskVoid Start()
|
||||||
|
{
|
||||||
|
//UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty)
|
||||||
|
// .Do(_ => { }, () => Debug.Log("COMPLETED"))
|
||||||
|
// .ForEachAsync(x =>
|
||||||
|
// {
|
||||||
|
// Debug.Log("VALUE_CHANGED:" + x);
|
||||||
|
// })
|
||||||
|
// .Forget();
|
||||||
|
|
||||||
pubsub.Subscribe().ForEachAsync(x => Debug.Log("A:" + x)).Forget();
|
//_ = Test1();
|
||||||
pubsub.Subscribe().ForEachAsync(x => Debug.Log("B:" + x)).Forget();
|
Test2().Forget();
|
||||||
|
//StartCoroutine(Test3("https://bing.com/"));
|
||||||
|
|
||||||
|
|
||||||
int i = 0;
|
// DG.Tweening.Core.TweenerCore<int>
|
||||||
|
//Debug.Log("GO MOVEX");
|
||||||
|
//await okButton.GetComponent<RectTransform>().DOMoveX(-10.2f, 3).WithCancellation(CancellationToken.None);
|
||||||
|
//Debug.Log("END MOVEX");
|
||||||
|
|
||||||
|
|
||||||
|
//Debug.Log("AGAIN MOVE");
|
||||||
|
//await okButton.GetComponent<RectTransform>().DOMoveY(10.2f, 3).WithCancellation(CancellationToken.None);
|
||||||
|
//Debug.Log("AGAIN END MOVE");
|
||||||
|
|
||||||
|
|
||||||
|
await UniTask.Yield();
|
||||||
|
// DOTween.To(
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
//var tween = okButton.GetComponent<RectTransform>().DOLocalMoveX(100, 5.0f);
|
||||||
|
|
||||||
|
cancelButton.OnClickAsAsyncEnumerable().ForEachAsync(_ =>
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
}).Forget();
|
||||||
|
|
||||||
|
|
||||||
|
// await tween.ToUniTask(TweenCancelBehaviour.KillAndCancelAwait, cts.Token);
|
||||||
|
|
||||||
|
//tween.SetRecyclable(true);
|
||||||
|
|
||||||
|
Debug.Log("END");
|
||||||
|
|
||||||
|
// tween.Play();
|
||||||
|
|
||||||
|
// DOTween.
|
||||||
|
|
||||||
|
// DOVirtual.Float(0, 1, 1, x => { }).ToUniTask();
|
||||||
|
|
||||||
okButton.OnClickAsAsyncEnumerable().ForEachAsync(_ =>
|
okButton.OnClickAsAsyncEnumerable().ForEachAsync(_ =>
|
||||||
{
|
{
|
||||||
|
|
||||||
Debug.Log("foo");
|
|
||||||
pubsub.Publish(i++);
|
|
||||||
|
|
||||||
|
|
||||||
}).Forget();
|
}).Forget();
|
||||||
|
|
||||||
|
CloseAsync(this.GetCancellationTokenOnDestroy()).Forget();
|
||||||
|
|
||||||
|
okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid CloseAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async UniTaskVoid Running(CancellationToken ct)
|
async UniTaskVoid Running(CancellationToken ct)
|
||||||
@@ -436,7 +599,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
public class ShowPlayerLoop
|
public class ShowPlayerLoop
|
||||||
{
|
{
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
static void Init()
|
static void Init()
|
||||||
{
|
{
|
||||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetDefaultPlayerLoop();
|
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetDefaultPlayerLoop();
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
|
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
await ToaruCoroutineEnumerator(); // wait 5 frame:)
|
await ToaruCoroutineEnumerator(); // wait 5 frame:)
|
||||||
await ToaruCoroutineEnumerator().ConfigureAwait(PlayerLoopTiming.PostLateUpdate);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
|
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
await ToaruCoroutineEnumerator(); // wait 5 frame:)
|
await ToaruCoroutineEnumerator(); // wait 5 frame:)
|
||||||
await ToaruCoroutineEnumerator().ConfigureAwait(PlayerLoopTiming.PostLateUpdate);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
"UnityEditor.TestRunner",
|
"UnityEditor.TestRunner",
|
||||||
"UniTask.Tests",
|
"UniTask.Tests",
|
||||||
"UniTask",
|
"UniTask",
|
||||||
"Unity.ResourceManager"
|
"Unity.ResourceManager",
|
||||||
|
"DOTween.Modules"
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
@@ -14,7 +15,8 @@
|
|||||||
"allowUnsafeCode": false,
|
"allowUnsafeCode": false,
|
||||||
"overrideReferences": true,
|
"overrideReferences": true,
|
||||||
"precompiledReferences": [
|
"precompiledReferences": [
|
||||||
"nunit.framework.dll"
|
"nunit.framework.dll",
|
||||||
|
"DOTween.dll"
|
||||||
],
|
],
|
||||||
"autoReferenced": false,
|
"autoReferenced": false,
|
||||||
"defineConstraints": [
|
"defineConstraints": [
|
||||||
|
|||||||
165
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs
Normal file
165
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#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 UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityEngine.Scripting;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Unity.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.TasksTests
|
||||||
|
{
|
||||||
|
public class GenericsWhenAllAny
|
||||||
|
{
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WhenAllT15() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var t01 = Tes<int>();
|
||||||
|
var t02 = Tes<int>();
|
||||||
|
var t03 = Tes<int>();
|
||||||
|
var t04 = Tes<int>();
|
||||||
|
var t05 = Tes<int>();
|
||||||
|
var t06 = Tes<int>();
|
||||||
|
var t07 = Tes<int>();
|
||||||
|
var t08 = Tes<int>();
|
||||||
|
var t09 = Tes<int>();
|
||||||
|
var t10 = Tes<int>();
|
||||||
|
var t11 = Tes<int>();
|
||||||
|
var t12 = Tes<int>();
|
||||||
|
var t13 = Tes<int>();
|
||||||
|
var t14 = Tes<int>();
|
||||||
|
var t15 = Tes<int>();
|
||||||
|
|
||||||
|
await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WhenAllT01_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var t01 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
await UniTask.WhenAll(t01);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WhenAllT02_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var t01 = Tes<MyGenerics<int>>();
|
||||||
|
var t02 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
await UniTask.WhenAll(t01, t02);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WhenAllT03_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var t01 = Tes<MyGenerics<int>>();
|
||||||
|
var t02 = Tes<MyGenerics<int>>();
|
||||||
|
var t03 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
await UniTask.WhenAll(t01, t02, t03);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WhenAllT04_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
var t01 = Tes<MyGenerics<int>>();
|
||||||
|
var t02 = Tes<MyGenerics<int>>();
|
||||||
|
var t03 = Tes<MyGenerics<int>>();
|
||||||
|
var t04 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
await UniTask.WhenAll(t01, t02, t03, t04);
|
||||||
|
});
|
||||||
|
|
||||||
|
// will fail.
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator WhenAllT05_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
//{
|
||||||
|
// var t01 = Tes<MyGenerics<int>>();
|
||||||
|
// var t02 = Tes<MyGenerics<int>>();
|
||||||
|
// var t03 = Tes<MyGenerics<int>>();
|
||||||
|
// var t04 = Tes<MyGenerics<int>>();
|
||||||
|
// var t05 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
// await UniTask.WhenAll(t01, t02, t03, t04, t05);
|
||||||
|
//});
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator WhenAllT06_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
//{
|
||||||
|
// var t01 = Tes<MyGenerics<int>>();
|
||||||
|
// var t02 = Tes<MyGenerics<int>>();
|
||||||
|
// var t03 = Tes<MyGenerics<int>>();
|
||||||
|
// var t04 = Tes<MyGenerics<int>>();
|
||||||
|
// var t05 = Tes<MyGenerics<int>>();
|
||||||
|
// var t06 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06);
|
||||||
|
//});
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator WhenAllT07_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
//{
|
||||||
|
// var t01 = Tes<MyGenerics<int>>();
|
||||||
|
// var t02 = Tes<MyGenerics<int>>();
|
||||||
|
// var t03 = Tes<MyGenerics<int>>();
|
||||||
|
// var t04 = Tes<MyGenerics<int>>();
|
||||||
|
// var t05 = Tes<MyGenerics<int>>();
|
||||||
|
// var t06 = Tes<MyGenerics<int>>();
|
||||||
|
// var t07 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07);
|
||||||
|
//});
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator WhenAllT15_Generics1() => UniTask.ToCoroutine(async () =>
|
||||||
|
//{
|
||||||
|
// var t01 = Tes<MyGenerics<int>>();
|
||||||
|
// var t02 = Tes<MyGenerics<int>>();
|
||||||
|
// var t03 = Tes<MyGenerics<int>>();
|
||||||
|
// var t04 = Tes<MyGenerics<int>>();
|
||||||
|
// var t05 = Tes<MyGenerics<int>>();
|
||||||
|
// var t06 = Tes<MyGenerics<int>>();
|
||||||
|
// var t07 = Tes<MyGenerics<int>>();
|
||||||
|
// var t08 = Tes<MyGenerics<int>>();
|
||||||
|
// var t09 = Tes<MyGenerics<int>>();
|
||||||
|
// var t10 = Tes<MyGenerics<int>>();
|
||||||
|
// var t11 = Tes<MyGenerics<int>>();
|
||||||
|
// var t12 = Tes<MyGenerics<int>>();
|
||||||
|
// var t13 = Tes<MyGenerics<int>>();
|
||||||
|
// var t14 = Tes<MyGenerics<int>>();
|
||||||
|
// var t15 = Tes<MyGenerics<int>>();
|
||||||
|
|
||||||
|
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15);
|
||||||
|
//});
|
||||||
|
|
||||||
|
async UniTask<T> Tes<T>()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyGenerics<T>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyGenerics2
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
11
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs.meta
Normal file
11
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6ce87069a3c0ebb47b26dca280a07756
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -4,14 +4,16 @@
|
|||||||
"UnityEngine.TestRunner",
|
"UnityEngine.TestRunner",
|
||||||
"UnityEditor.TestRunner",
|
"UnityEditor.TestRunner",
|
||||||
"UniTask",
|
"UniTask",
|
||||||
"Unity.ResourceManager"
|
"Unity.ResourceManager",
|
||||||
|
"DOTween.Modules"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
"allowUnsafeCode": false,
|
"allowUnsafeCode": false,
|
||||||
"overrideReferences": true,
|
"overrideReferences": true,
|
||||||
"precompiledReferences": [
|
"precompiledReferences": [
|
||||||
"nunit.framework.dll"
|
"nunit.framework.dll",
|
||||||
|
"DOTween.dll"
|
||||||
],
|
],
|
||||||
"autoReferenced": false,
|
"autoReferenced": false,
|
||||||
"defineConstraints": [
|
"defineConstraints": [
|
||||||
|
|||||||
Reference in New Issue
Block a user