mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-16 12:00:10 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85fb08552e | ||
|
|
7bd4b6faf7 | ||
|
|
0b1ae7e295 | ||
|
|
35a893ad9e | ||
|
|
4955ed18f1 | ||
|
|
fe462328ab | ||
|
|
5136d92efa | ||
|
|
227f7872cb | ||
|
|
725b2fdc35 | ||
|
|
75abc8059f | ||
|
|
f1193743c8 | ||
|
|
109730eacd | ||
|
|
1f736afe86 | ||
|
|
4d554a6718 | ||
|
|
69c0c362e9 | ||
|
|
3bb446556a | ||
|
|
ea950d8cec | ||
|
|
a65f4da7a2 | ||
|
|
0bdc933c20 | ||
|
|
0c0f79c6db | ||
|
|
32f9b9d4ac | ||
|
|
53907a3719 | ||
|
|
4937aeee3f | ||
|
|
5e5b8aff89 | ||
|
|
a2cbbd82d0 | ||
|
|
7eac5d8ba8 | ||
|
|
e2b1ed55ae | ||
|
|
727c7102d3 | ||
|
|
1494ea6717 | ||
|
|
f1ce64dbd3 | ||
|
|
3bad5cd2bf | ||
|
|
7432c0073a | ||
|
|
f1813a7c94 | ||
|
|
9e45c0a4d1 | ||
|
|
2c652cdde7 | ||
|
|
7718d345c8 | ||
|
|
9f39708325 | ||
|
|
bb6dbfa920 | ||
|
|
ba265005bb | ||
|
|
4d7cc7ed61 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -253,3 +253,5 @@ src/UniTask/UnityEngine.UI.Player.csproj
|
|||||||
src/UniTask/DOTween.Modules.Player.csproj
|
src/UniTask/DOTween.Modules.Player.csproj
|
||||||
|
|
||||||
src/UniTask/Assembly-CSharp.Player.csproj
|
src/UniTask/Assembly-CSharp.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.EditorCoroutines.Editor.csproj
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -32,6 +32,9 @@ Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await f
|
|||||||
- [Awaitable Events](#awaitable-events)
|
- [Awaitable Events](#awaitable-events)
|
||||||
- [Channel](#channel)
|
- [Channel](#channel)
|
||||||
- [For Unit Testing](#for-unit-testing)
|
- [For Unit Testing](#for-unit-testing)
|
||||||
|
- [ThreadPool limitation](#threadpool-limitation)
|
||||||
|
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
||||||
|
- [For UnityEditor](#for-unityeditor)
|
||||||
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||||
- [Pooling Configuration](#pooling-configuration)
|
- [Pooling Configuration](#pooling-configuration)
|
||||||
- [Allocation on Profiler](#allocation-on-profiler)
|
- [Allocation on Profiler](#allocation-on-profiler)
|
||||||
@@ -489,6 +492,8 @@ await UniTask.WhenAll(
|
|||||||
transform.DOScale(10, 3).WithCancellation(ct));
|
transform.DOScale(10, 3).WithCancellation(ct));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
DOTween support's default behaviour(`await`, `WithCancellation`, `ToUniTask`) awaits tween is killed. It works both Complete(true/false) and Kill(true/false). But if you want to tween reuse(`SetAutoKill(false)`), it does not work you expected. Or, if you want to await for another timing, the following extension methods exist in Tween, `AwaitForComplete`, `AwaitForPause`, `AwaitForPlay`, `AwaitForRewind`, `AwaitForStepComplete`.
|
||||||
|
|
||||||
AsyncEnumerable and Async LINQ
|
AsyncEnumerable and Async LINQ
|
||||||
---
|
---
|
||||||
Unity 2020.2.0a12 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in async era.
|
Unity 2020.2.0a12 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in async era.
|
||||||
@@ -778,6 +783,26 @@ public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
|
|||||||
|
|
||||||
UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working.
|
UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working.
|
||||||
|
|
||||||
|
ThreadPool limitation
|
||||||
|
---
|
||||||
|
Most UniTask methods run in a single thread (PlayerLoop), but only `UniTask.Run` and `UniTask.SwitchToThreadPool` run on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
|
||||||
|
|
||||||
|
`UniTask.Run` will be deprecated in the future (marked with an Obsolete) and only `RunOnThreadPool` will be used. Also, if you use `UniTask.Run`, consider whether you can use `UniTask.Create` or `UniTask.Void`.
|
||||||
|
|
||||||
|
IEnumerator.ToUniTask limitation
|
||||||
|
---
|
||||||
|
You can convert coroutine(IEnumerator) to UniTask(or await directly) but has some limitations.
|
||||||
|
|
||||||
|
* `WaitForEndOfFrame`/`WaitForFixedUpdate` is not supported, used `yield return null` instead.
|
||||||
|
* Consuming loop timing is not same as StartCoroutine, it is used specified PlayerLoopTiming, and default's `PlayerLoopTiming.Update` is run before MonoBehaviour's Update and StartCoroutine's loop.
|
||||||
|
|
||||||
|
For UnityEditor
|
||||||
|
---
|
||||||
|
UniTask can run on Unity Edtitor like Editor Coroutine. However, there are some limitations.
|
||||||
|
|
||||||
|
* Delay, DelayFrame is not work correctly because can not get deltaTime in editor. Return the result of the await immediately; you can use `DelayType.Realtime` to wait for the right time.
|
||||||
|
* All PlayerLoopTiming run on timing, `EditorApplication.update`.
|
||||||
|
|
||||||
Compare with Standard Task API
|
Compare with Standard Task API
|
||||||
---
|
---
|
||||||
UniTask has many standard Task-like APIs. This table shows what is the alternative apis.
|
UniTask has many standard Task-like APIs. This table shows what is the alternative apis.
|
||||||
@@ -880,7 +905,7 @@ After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of gi
|
|||||||
|
|
||||||
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` to `Packages/manifest.json`.
|
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` to `Packages/manifest.json`.
|
||||||
|
|
||||||
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.24`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.24`.
|
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.31`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.31`.
|
||||||
|
|
||||||
### Install via OpenUPM
|
### Install via OpenUPM
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||||
{
|
{
|
||||||
static TaskPool<ThreadPoolWorkItem> pool;
|
static TaskPool<ThreadPoolWorkItem> pool;
|
||||||
public ThreadPoolWorkItem NextNode { get; set; }
|
ThreadPoolWorkItem nextNode;
|
||||||
|
public ref ThreadPoolWorkItem NextNode => ref nextNode;
|
||||||
|
|
||||||
static ThreadPoolWorkItem()
|
static ThreadPoolWorkItem()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ public class QueueCheck
|
|||||||
{
|
{
|
||||||
Node node1 = new Node();
|
Node node1 = new Node();
|
||||||
Node node2 = new Node();
|
Node node2 = new Node();
|
||||||
|
RefNode refNode1 = new RefNode();
|
||||||
|
RefNode refNode2 = new RefNode();
|
||||||
Queue<Node> q1 = new Queue<Node>();
|
Queue<Node> q1 = new Queue<Node>();
|
||||||
Stack<Node> s1 = new Stack<Node>();
|
Stack<Node> s1 = new Stack<Node>();
|
||||||
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
|
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
|
||||||
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
|
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
|
||||||
static TaskPool<Node> pool;
|
static TaskPool<Node> pool;
|
||||||
|
static TaskPoolRefNode<RefNode> poolRefNode;
|
||||||
static TaskPoolEqualNull<Node> poolEqualNull;
|
static TaskPoolEqualNull<Node> poolEqualNull;
|
||||||
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
|
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
|
||||||
static TaskPoolWithoutSize<Node> poolWithoutSize;
|
static TaskPoolWithoutSize<Node> poolWithoutSize;
|
||||||
@@ -82,6 +85,14 @@ public class QueueCheck
|
|||||||
pool.TryPop(out _);
|
pool.TryPop(out _);
|
||||||
pool.TryPop(out _);
|
pool.TryPop(out _);
|
||||||
}
|
}
|
||||||
|
[Benchmark]
|
||||||
|
public void TaskPoolRefNode()
|
||||||
|
{
|
||||||
|
poolRefNode.TryPush(refNode1);
|
||||||
|
poolRefNode.TryPush(refNode2);
|
||||||
|
poolRefNode.TryPop(out _);
|
||||||
|
poolRefNode.TryPop(out _);
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void TaskPoolEqualNull()
|
public void TaskPoolEqualNull()
|
||||||
@@ -130,6 +141,18 @@ public interface ITaskPoolNode<T>
|
|||||||
T NextNode { get; set; }
|
T NextNode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class RefNode :ITaskPoolRefNode<RefNode>
|
||||||
|
{
|
||||||
|
RefNode nextNode;
|
||||||
|
public ref RefNode NextNode => ref nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ITaskPoolRefNode<T>
|
||||||
|
{
|
||||||
|
ref T NextNode { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// mutable struct, don't mark readonly.
|
// mutable struct, don't mark readonly.
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct TaskPoolWithoutLock<T>
|
public struct TaskPoolWithoutLock<T>
|
||||||
@@ -237,6 +260,60 @@ public struct TaskPool<T>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct TaskPoolRefNode<T>
|
||||||
|
where T : class, ITaskPoolRefNode<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))
|
||||||
|
{
|
||||||
|
ref var nextNode = ref v.NextNode;
|
||||||
|
root = nextNode;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct TaskPoolEqualNull<T>
|
public struct TaskPoolEqualNull<T>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"allowUnsafeCode": false,
|
"allowUnsafeCode": false,
|
||||||
"overrideReferences": false,
|
"overrideReferences": false,
|
||||||
"precompiledReferences": [],
|
"precompiledReferences": [],
|
||||||
"autoReferenced": true,
|
"autoReferenced": false,
|
||||||
"defineConstraints": [],
|
"defineConstraints": [],
|
||||||
"versionDefines": [],
|
"versionDefines": [],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
static TaskPool<WaitAsyncSource> pool;
|
static TaskPool<WaitAsyncSource> pool;
|
||||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
WaitAsyncSource nextNode;
|
||||||
|
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitAsyncSource()
|
static WaitAsyncSource()
|
||||||
{
|
{
|
||||||
@@ -404,7 +405,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
static TaskPool<WaitAsyncSource> pool;
|
static TaskPool<WaitAsyncSource> pool;
|
||||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
WaitAsyncSource nextNode;
|
||||||
|
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitAsyncSource()
|
static WaitAsyncSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return ToCancellationToken(task);
|
return ToCancellationToken(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
|
||||||
ToCancellationTokenCore(task, cts).Forget();
|
ToCancellationTokenCore(task, cts).Forget();
|
||||||
|
|
||||||
return CancellationTokenSource.CreateLinkedTokenSource(linkToken).Token;
|
return cts.Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
|
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncUniTaskVoid<TStateMachine> NextNode { get; set; }
|
AsyncUniTaskVoid<TStateMachine> nextNode;
|
||||||
|
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
|
||||||
|
|
||||||
public void Return()
|
public void Return()
|
||||||
{
|
{
|
||||||
@@ -157,7 +158,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncUniTask<TStateMachine> NextNode { get; set; }
|
AsyncUniTask<TStateMachine> nextNode;
|
||||||
|
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncUniTask()
|
static AsyncUniTask()
|
||||||
{
|
{
|
||||||
@@ -279,7 +281,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
AsyncUniTask<TStateMachine, T> nextNode;
|
||||||
|
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncUniTask()
|
static AsyncUniTask()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<EnumeratorPromise> pool;
|
static TaskPool<EnumeratorPromise> pool;
|
||||||
public EnumeratorPromise NextNode { get; set; }
|
EnumeratorPromise nextNode;
|
||||||
|
public ref EnumeratorPromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static EnumeratorPromise()
|
static EnumeratorPromise()
|
||||||
{
|
{
|
||||||
@@ -162,11 +163,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
else if (current is CustomYieldInstruction)
|
else if (current is CustomYieldInstruction cyi)
|
||||||
{
|
{
|
||||||
// WWW, WaitForSecondsRealtime
|
// WWW, WaitForSecondsRealtime
|
||||||
var e2 = UnwrapWaitCustomYieldInstruction((CustomYieldInstruction)current);
|
while (cyi.keepWaiting)
|
||||||
while (e2.MoveNext())
|
|
||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
@@ -211,26 +211,17 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WWW and others as CustomYieldInstruction.
|
|
||||||
static IEnumerator UnwrapWaitCustomYieldInstruction(CustomYieldInstruction yieldInstruction)
|
|
||||||
{
|
|
||||||
while (yieldInstruction.keepWaiting)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly FieldInfo waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
|
static readonly FieldInfo waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
|
||||||
|
|
||||||
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
|
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
|
||||||
{
|
{
|
||||||
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
|
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
|
||||||
var startTime = DateTimeOffset.UtcNow;
|
var elapsed = 0.0f;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
var elapsed = (DateTimeOffset.UtcNow - startTime).TotalSeconds;
|
elapsed += Time.deltaTime;
|
||||||
if (elapsed >= second)
|
if (elapsed >= second)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static class AddressablesAsyncExtensions
|
public static class AddressablesAsyncExtensions
|
||||||
{
|
{
|
||||||
#region AsyncOperationHandle
|
#region AsyncOperationHandle
|
||||||
|
|
||||||
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||||
{
|
{
|
||||||
@@ -94,7 +94,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||||
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
AsyncOperationHandleConfiguredSource nextNode;
|
||||||
|
public ref AsyncOperationHandleConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
static AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -221,9 +222,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AsyncOperationHandle_T
|
#region AsyncOperationHandle_T
|
||||||
|
|
||||||
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||||
{
|
{
|
||||||
@@ -259,7 +260,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||||
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
AsyncOperationHandleConfiguredSource<T> nextNode;
|
||||||
|
public ref AsyncOperationHandleConfiguredSource<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
static AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -391,7 +393,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
// The idea of TweenCancelBehaviour is borrowed from https://www.shibuya24.info/entry/dotween_async_await
|
|
||||||
public enum TweenCancelBehaviour
|
public enum TweenCancelBehaviour
|
||||||
{
|
{
|
||||||
Kill,
|
Kill,
|
||||||
@@ -29,6 +28,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
public static class DOTweenAsyncExtensions
|
public static class DOTweenAsyncExtensions
|
||||||
{
|
{
|
||||||
|
enum CallbackType
|
||||||
|
{
|
||||||
|
Kill,
|
||||||
|
Complete,
|
||||||
|
Pause,
|
||||||
|
Play,
|
||||||
|
Rewind,
|
||||||
|
StepComplete
|
||||||
|
}
|
||||||
|
|
||||||
public static TweenAwaiter GetAwaiter(this Tween tween)
|
public static TweenAwaiter GetAwaiter(this Tween tween)
|
||||||
{
|
{
|
||||||
return new TweenAwaiter(tween);
|
return new TweenAwaiter(tween);
|
||||||
@@ -39,7 +48,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, out var token), token);
|
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||||
@@ -47,7 +56,47 @@ namespace Cysharp.Threading.Tasks
|
|||||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||||
|
|
||||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, out var token), token);
|
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Kill, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask AwaitForComplete(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, CallbackType.Complete, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask AwaitForPause(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, CallbackType.Pause, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask AwaitForPlay(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, CallbackType.Play, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask AwaitForRewind(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, CallbackType.Rewind, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask AwaitForStepComplete(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, CallbackType.StepComplete, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct TweenAwaiter : ICriticalNotifyCompletion
|
public struct TweenAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -86,7 +135,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<TweenConfiguredSource> pool;
|
static TaskPool<TweenConfiguredSource> pool;
|
||||||
public TweenConfiguredSource NextNode { get; set; }
|
TweenConfiguredSource nextNode;
|
||||||
|
public ref TweenConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static TweenConfiguredSource()
|
static TweenConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -95,12 +145,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||||
|
|
||||||
readonly TweenCallback onKillDelegate;
|
readonly TweenCallback onCompleteCallbackDelegate;
|
||||||
readonly TweenCallback onUpdateDelegate;
|
readonly TweenCallback onUpdateDelegate;
|
||||||
|
|
||||||
Tween tween;
|
Tween tween;
|
||||||
TweenCancelBehaviour cancelBehaviour;
|
TweenCancelBehaviour cancelBehaviour;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
|
CallbackType callbackType;
|
||||||
bool canceled;
|
bool canceled;
|
||||||
|
|
||||||
TweenCallback originalUpdateAction;
|
TweenCallback originalUpdateAction;
|
||||||
@@ -108,11 +159,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
TweenConfiguredSource()
|
TweenConfiguredSource()
|
||||||
{
|
{
|
||||||
onKillDelegate = OnKill;
|
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
|
||||||
onUpdateDelegate = OnUpdate;
|
onUpdateDelegate = OnUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
|
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -128,6 +179,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.tween = tween;
|
result.tween = tween;
|
||||||
result.cancelBehaviour = cancelBehaviour;
|
result.cancelBehaviour = cancelBehaviour;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.callbackType = callbackType;
|
||||||
|
|
||||||
result.originalUpdateAction = tween.onUpdate;
|
result.originalUpdateAction = tween.onUpdate;
|
||||||
result.canceled = false;
|
result.canceled = false;
|
||||||
@@ -138,7 +190,30 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
tween.onUpdate = result.onUpdateDelegate;
|
tween.onUpdate = result.onUpdateDelegate;
|
||||||
tween.onKill = result.onKillDelegate;
|
|
||||||
|
switch (callbackType)
|
||||||
|
{
|
||||||
|
case CallbackType.Kill:
|
||||||
|
tween.onKill = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
case CallbackType.Complete:
|
||||||
|
tween.onComplete = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
case CallbackType.Pause:
|
||||||
|
tween.onPause = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
case CallbackType.Play:
|
||||||
|
tween.onPlay = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
case CallbackType.Rewind:
|
||||||
|
tween.onRewind = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
case CallbackType.StepComplete:
|
||||||
|
tween.onStepComplete = result.onCompleteCallbackDelegate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
@@ -146,7 +221,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnKill()
|
void OnCompleteCallbackDelegate()
|
||||||
{
|
{
|
||||||
if (canceled)
|
if (canceled)
|
||||||
{
|
{
|
||||||
@@ -199,7 +274,31 @@ namespace Cysharp.Threading.Tasks
|
|||||||
this.tween.Complete(true);
|
this.tween.Complete(true);
|
||||||
break;
|
break;
|
||||||
case TweenCancelBehaviour.CancelAwait:
|
case TweenCancelBehaviour.CancelAwait:
|
||||||
this.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
// replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
||||||
|
switch (callbackType)
|
||||||
|
{
|
||||||
|
case CallbackType.Kill:
|
||||||
|
tween.onKill = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
case CallbackType.Complete:
|
||||||
|
tween.onComplete = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
case CallbackType.Pause:
|
||||||
|
tween.onPause = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
case CallbackType.Play:
|
||||||
|
tween.onPlay = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
case CallbackType.Rewind:
|
||||||
|
tween.onRewind = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
case CallbackType.StepComplete:
|
||||||
|
tween.onStepComplete = EmptyTweenCallback;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
this.core.TrySetCanceled(this.cancellationToken);
|
this.core.TrySetCanceled(this.cancellationToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -272,7 +371,31 @@ namespace Cysharp.Threading.Tasks
|
|||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
core.Reset();
|
core.Reset();
|
||||||
tween.onUpdate = originalUpdateAction;
|
tween.onUpdate = originalUpdateAction;
|
||||||
tween.onKill = null;
|
|
||||||
|
switch (callbackType)
|
||||||
|
{
|
||||||
|
case CallbackType.Kill:
|
||||||
|
tween.onKill = null;
|
||||||
|
break;
|
||||||
|
case CallbackType.Complete:
|
||||||
|
tween.onComplete = null;
|
||||||
|
break;
|
||||||
|
case CallbackType.Pause:
|
||||||
|
tween.onPause = null;
|
||||||
|
break;
|
||||||
|
case CallbackType.Play:
|
||||||
|
tween.onPlay = null;
|
||||||
|
break;
|
||||||
|
case CallbackType.Rewind:
|
||||||
|
tween.onRewind = null;
|
||||||
|
break;
|
||||||
|
case CallbackType.StepComplete:
|
||||||
|
tween.onStepComplete = null;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
tween = default;
|
tween = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
originalUpdateAction = default;
|
originalUpdateAction = default;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static partial class TextMeshProAsyncExtensions
|
public static partial class TextMeshProAsyncExtensions
|
||||||
{
|
{
|
||||||
|
// <string> -> Text
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
|
||||||
{
|
{
|
||||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
@@ -62,6 +63,67 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <T> -> Text
|
||||||
|
|
||||||
|
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo<T>(this AsyncReactiveProperty<T> source, TMP_Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
text.text = e.Current.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ namespace Cysharp.Threading.Tasks.Internal
|
|||||||
|
|
||||||
for (int i = 0; i < actionListCount; i++)
|
for (int i = 0; i < actionListCount; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
var action = actionList[i];
|
var action = actionList[i];
|
||||||
actionList[i] = null;
|
actionList[i] = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
action();
|
action();
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ namespace Cysharp.Threading.Tasks.Internal
|
|||||||
{
|
{
|
||||||
var j = tail - 1;
|
var j = tail - 1;
|
||||||
|
|
||||||
|
var loopItems = this.loopItems;
|
||||||
// eliminate array-bound check for i
|
// eliminate array-bound check for i
|
||||||
for (int i = 0; i < loopItems.Length; i++)
|
for (int i = 0; i < loopItems.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ namespace Cysharp.Threading.Tasks.Internal
|
|||||||
{
|
{
|
||||||
static TaskPool<PooledDelegate<T>> pool;
|
static TaskPool<PooledDelegate<T>> pool;
|
||||||
|
|
||||||
public PooledDelegate<T> NextNode { get; set; }
|
PooledDelegate<T> nextNode;
|
||||||
|
public ref PooledDelegate<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
static PooledDelegate()
|
static PooledDelegate()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,6 +63,42 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
// OnNext, OnError
|
// OnNext, OnError
|
||||||
|
|
||||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||||
@@ -105,6 +141,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
// OnNext, OnCompleted
|
// OnNext, OnCompleted
|
||||||
|
|
||||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||||
@@ -147,6 +223,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||||
|
|
||||||
|
var cts = new CancellationTokenDisposable();
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||||
|
return cts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(source, nameof(source));
|
||||||
|
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||||
|
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||||
|
|
||||||
|
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
// IObserver
|
// IObserver
|
||||||
|
|
||||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
||||||
@@ -195,7 +311,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
while (await e.MoveNextAsync())
|
while (await e.MoveNextAsync())
|
||||||
{
|
{
|
||||||
onNext(e.Current);
|
try
|
||||||
|
{
|
||||||
|
onNext(e.Current);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onCompleted();
|
onCompleted();
|
||||||
}
|
}
|
||||||
@@ -227,7 +350,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
while (await e.MoveNextAsync())
|
while (await e.MoveNextAsync())
|
||||||
{
|
{
|
||||||
onNext(e.Current).Forget();
|
try
|
||||||
|
{
|
||||||
|
onNext(e.Current).Forget();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onCompleted();
|
onCompleted();
|
||||||
}
|
}
|
||||||
@@ -259,7 +389,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
while (await e.MoveNextAsync())
|
while (await e.MoveNextAsync())
|
||||||
{
|
{
|
||||||
onNext(e.Current, cancellationToken).Forget();
|
try
|
||||||
|
{
|
||||||
|
onNext(e.Current, cancellationToken).Forget();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onCompleted();
|
onCompleted();
|
||||||
}
|
}
|
||||||
@@ -291,7 +428,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
while (await e.MoveNextAsync())
|
while (await e.MoveNextAsync())
|
||||||
{
|
{
|
||||||
observer.OnNext(e.Current);
|
try
|
||||||
|
{
|
||||||
|
observer.OnNext(e.Current);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
observer.OnCompleted();
|
observer.OnCompleted();
|
||||||
}
|
}
|
||||||
@@ -309,5 +453,84 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (await e.MoveNextAsync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await onNext(e.Current);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onCompleted();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (onError == NopError)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
onError(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (await e.MoveNextAsync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await onNext(e.Current, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onCompleted();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (onError == NopError)
|
||||||
|
{
|
||||||
|
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
onError(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,8 +19,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// UnityEngine.Debug.Log("Called ToArray");
|
|
||||||
|
|
||||||
var pool = ArrayPool<TSource>.Shared;
|
var pool = ArrayPool<TSource>.Shared;
|
||||||
var array = pool.Rent(16);
|
var array = pool.Rent(16);
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.Log("TRY_RESULT:" + target.TryGetTarget(out var _));
|
|
||||||
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
||||||
{
|
{
|
||||||
completionSource.TrySetResult(false);
|
completionSource.TrySetResult(false);
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
// Initialization
|
// Initialization
|
||||||
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization),
|
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization),
|
||||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(PlayerLoopTiming.LastInitialization),
|
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(PlayerLoopTiming.LastInitialization),
|
||||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[0] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
||||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.LastInitialization));
|
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.LastInitialization));
|
||||||
// EarlyUpdate
|
// EarlyUpdate
|
||||||
copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
|
copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
public interface ITaskPoolNode<T>
|
public interface ITaskPoolNode<T>
|
||||||
{
|
{
|
||||||
T NextNode { get; set; }
|
ref T NextNode { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutable struct, don't mark readonly.
|
// mutable struct, don't mark readonly.
|
||||||
@@ -77,8 +77,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
var v = root;
|
var v = root;
|
||||||
if (!(v is null))
|
if (!(v is null))
|
||||||
{
|
{
|
||||||
root = v.NextNode;
|
ref var nextNode = ref v.NextNode;
|
||||||
v.NextNode = null;
|
root = nextNode;
|
||||||
|
nextNode = null;
|
||||||
size--;
|
size--;
|
||||||
result = v;
|
result = v;
|
||||||
Volatile.Write(ref gate, 0);
|
Volatile.Write(ref gate, 0);
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<YieldPromise> pool;
|
static TaskPool<YieldPromise> pool;
|
||||||
public YieldPromise NextNode { get; set; }
|
YieldPromise nextNode;
|
||||||
|
public ref YieldPromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static YieldPromise()
|
static YieldPromise()
|
||||||
{
|
{
|
||||||
@@ -215,7 +216,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
|
sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<NextFramePromise> pool;
|
static TaskPool<NextFramePromise> pool;
|
||||||
public NextFramePromise NextNode { get; set; }
|
NextFramePromise nextNode;
|
||||||
|
public ref NextFramePromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static NextFramePromise()
|
static NextFramePromise()
|
||||||
{
|
{
|
||||||
@@ -309,7 +311,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<DelayFramePromise> pool;
|
static TaskPool<DelayFramePromise> pool;
|
||||||
public DelayFramePromise NextNode { get; set; }
|
DelayFramePromise nextNode;
|
||||||
|
public ref DelayFramePromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static DelayFramePromise()
|
static DelayFramePromise()
|
||||||
{
|
{
|
||||||
@@ -424,7 +427,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
|
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<DelayPromise> pool;
|
static TaskPool<DelayPromise> pool;
|
||||||
public DelayPromise NextNode { get; set; }
|
DelayPromise nextNode;
|
||||||
|
public ref DelayPromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static DelayPromise()
|
static DelayPromise()
|
||||||
{
|
{
|
||||||
@@ -534,7 +538,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
|
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<DelayIgnoreTimeScalePromise> pool;
|
static TaskPool<DelayIgnoreTimeScalePromise> pool;
|
||||||
public DelayIgnoreTimeScalePromise NextNode { get; set; }
|
DelayIgnoreTimeScalePromise nextNode;
|
||||||
|
public ref DelayIgnoreTimeScalePromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static DelayIgnoreTimeScalePromise()
|
static DelayIgnoreTimeScalePromise()
|
||||||
{
|
{
|
||||||
@@ -644,7 +649,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class DelayRealtimePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayRealtimePromise>
|
sealed class DelayRealtimePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayRealtimePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<DelayRealtimePromise> pool;
|
static TaskPool<DelayRealtimePromise> pool;
|
||||||
public DelayRealtimePromise NextNode { get; set; }
|
DelayRealtimePromise nextNode;
|
||||||
|
public ref DelayRealtimePromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static DelayRealtimePromise()
|
static DelayRealtimePromise()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public partial struct UniTask
|
public partial struct UniTask
|
||||||
{
|
{
|
||||||
|
#region OBSOLETE_RUN
|
||||||
|
|
||||||
|
// Run is a confusing name, use only RunOnThreadPool in the future.
|
||||||
|
|
||||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -232,6 +236,235 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask RunOnThreadPool(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action(state);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
action(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask RunOnThreadPool(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await action();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await action();
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask RunOnThreadPool(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await action(state);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await action(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask<T> RunOnThreadPool<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask<T> RunOnThreadPool<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await func();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
await UniTask.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = await func();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask<T> RunOnThreadPool<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return func(state);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return func(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||||
|
public static async UniTask<T> RunOnThreadPool<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await UniTask.SwitchToThreadPool();
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (configureAwait)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await func(state);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
await UniTask.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = await func(state);
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||||
{
|
{
|
||||||
static TaskPool<ThreadPoolWorkItem> pool;
|
static TaskPool<ThreadPoolWorkItem> pool;
|
||||||
public ThreadPoolWorkItem NextNode { get; set; }
|
ThreadPoolWorkItem nextNode;
|
||||||
|
public ref ThreadPoolWorkItem NextNode => ref nextNode;
|
||||||
|
|
||||||
static ThreadPoolWorkItem()
|
static ThreadPoolWorkItem()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitUntilPromise> pool;
|
static TaskPool<WaitUntilPromise> pool;
|
||||||
public WaitUntilPromise NextNode { get; set; }
|
WaitUntilPromise nextNode;
|
||||||
|
public ref WaitUntilPromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitUntilPromise()
|
static WaitUntilPromise()
|
||||||
{
|
{
|
||||||
@@ -142,7 +143,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitWhilePromise> pool;
|
static TaskPool<WaitWhilePromise> pool;
|
||||||
public WaitWhilePromise NextNode { get; set; }
|
WaitWhilePromise nextNode;
|
||||||
|
public ref WaitWhilePromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitWhilePromise()
|
static WaitWhilePromise()
|
||||||
{
|
{
|
||||||
@@ -246,7 +248,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||||
public WaitUntilCanceledPromise NextNode { get; set; }
|
WaitUntilCanceledPromise nextNode;
|
||||||
|
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitUntilCanceledPromise()
|
static WaitUntilCanceledPromise()
|
||||||
{
|
{
|
||||||
@@ -334,7 +337,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedUnityObjectPromise<T, U>>
|
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedUnityObjectPromise<T, U>>
|
||||||
{
|
{
|
||||||
static TaskPool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool;
|
static TaskPool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool;
|
||||||
public WaitUntilValueChangedUnityObjectPromise<T, U> NextNode { get; set; }
|
WaitUntilValueChangedUnityObjectPromise<T, U> nextNode;
|
||||||
|
public ref WaitUntilValueChangedUnityObjectPromise<T, U> NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitUntilValueChangedUnityObjectPromise()
|
static WaitUntilValueChangedUnityObjectPromise()
|
||||||
{
|
{
|
||||||
@@ -457,7 +461,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
static TaskPool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool;
|
static TaskPool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool;
|
||||||
public WaitUntilValueChangedStandardObjectPromise<T, U> NextNode { get; set; }
|
WaitUntilValueChangedStandardObjectPromise<T, U> nextNode;
|
||||||
|
public ref WaitUntilValueChangedStandardObjectPromise<T, U> NextNode => ref nextNode;
|
||||||
|
|
||||||
static WaitUntilValueChangedStandardObjectPromise()
|
static WaitUntilValueChangedStandardObjectPromise()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -319,7 +319,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
|
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
|
||||||
{
|
{
|
||||||
static TaskPool<AutoResetUniTaskCompletionSource> pool;
|
static TaskPool<AutoResetUniTaskCompletionSource> pool;
|
||||||
public AutoResetUniTaskCompletionSource NextNode { get; set; }
|
AutoResetUniTaskCompletionSource nextNode;
|
||||||
|
public ref AutoResetUniTaskCompletionSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AutoResetUniTaskCompletionSource()
|
static AutoResetUniTaskCompletionSource()
|
||||||
{
|
{
|
||||||
@@ -441,7 +442,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
|
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
|
||||||
{
|
{
|
||||||
static TaskPool<AutoResetUniTaskCompletionSource<T>> pool;
|
static TaskPool<AutoResetUniTaskCompletionSource<T>> pool;
|
||||||
public AutoResetUniTaskCompletionSource<T> NextNode { get; set; }
|
AutoResetUniTaskCompletionSource<T> nextNode;
|
||||||
|
public ref AutoResetUniTaskCompletionSource<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
static AutoResetUniTaskCompletionSource()
|
static AutoResetUniTaskCompletionSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -736,6 +736,26 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
await await task;
|
await await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task)
|
||||||
|
{
|
||||||
|
return await await task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async UniTask Unwrap<T>(this Task<UniTask> task)
|
||||||
|
{
|
||||||
|
await await task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task)
|
||||||
|
{
|
||||||
|
return await await task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async UniTask Unwrap<T>(this UniTask<Task> task)
|
||||||
|
{
|
||||||
|
await await task;
|
||||||
|
}
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleRequestAllAssetsWithCancellationSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsWithCancellationSource>
|
sealed class AssetBundleRequestAllAssetsWithCancellationSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleRequestAllAssetsWithCancellationSource> pool;
|
static TaskPool<AssetBundleRequestAllAssetsWithCancellationSource> pool;
|
||||||
public AssetBundleRequestAllAssetsWithCancellationSource NextNode { get; set; }
|
AssetBundleRequestAllAssetsWithCancellationSource nextNode;
|
||||||
|
public ref AssetBundleRequestAllAssetsWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleRequestAllAssetsWithCancellationSource()
|
static AssetBundleRequestAllAssetsWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -204,7 +205,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleRequestAllAssetsConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsConfiguredSource>
|
sealed class AssetBundleRequestAllAssetsConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleRequestAllAssetsConfiguredSource> pool;
|
static TaskPool<AssetBundleRequestAllAssetsConfiguredSource> pool;
|
||||||
public AssetBundleRequestAllAssetsConfiguredSource NextNode { get; set; }
|
AssetBundleRequestAllAssetsConfiguredSource nextNode;
|
||||||
|
public ref AssetBundleRequestAllAssetsConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleRequestAllAssetsConfiguredSource()
|
static AssetBundleRequestAllAssetsConfiguredSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
|
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
|
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
|
||||||
public AsyncGPUReadbackRequestAwaiterConfiguredSource NextNode { get; set; }
|
AsyncGPUReadbackRequestAwaiterConfiguredSource nextNode;
|
||||||
|
public ref AsyncGPUReadbackRequestAwaiterConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
static AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AsyncOperationWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationWithCancellationSource>
|
sealed class AsyncOperationWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncOperationWithCancellationSource> pool;
|
static TaskPool<AsyncOperationWithCancellationSource> pool;
|
||||||
public AsyncOperationWithCancellationSource NextNode { get; set; }
|
AsyncOperationWithCancellationSource nextNode;
|
||||||
|
public ref AsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncOperationWithCancellationSource()
|
static AsyncOperationWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -198,7 +199,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncOperationConfiguredSource> pool;
|
static TaskPool<AsyncOperationConfiguredSource> pool;
|
||||||
public AsyncOperationConfiguredSource NextNode { get; set; }
|
AsyncOperationConfiguredSource nextNode;
|
||||||
|
public ref AsyncOperationConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AsyncOperationConfiguredSource()
|
static AsyncOperationConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -374,7 +376,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class ResourceRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestWithCancellationSource>
|
sealed class ResourceRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<ResourceRequestWithCancellationSource> pool;
|
static TaskPool<ResourceRequestWithCancellationSource> pool;
|
||||||
public ResourceRequestWithCancellationSource NextNode { get; set; }
|
ResourceRequestWithCancellationSource nextNode;
|
||||||
|
public ref ResourceRequestWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static ResourceRequestWithCancellationSource()
|
static ResourceRequestWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -496,7 +499,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<ResourceRequestConfiguredSource> pool;
|
static TaskPool<ResourceRequestConfiguredSource> pool;
|
||||||
public ResourceRequestConfiguredSource NextNode { get; set; }
|
ResourceRequestConfiguredSource nextNode;
|
||||||
|
public ref ResourceRequestConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static ResourceRequestConfiguredSource()
|
static ResourceRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -677,7 +681,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestWithCancellationSource>
|
sealed class AssetBundleRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleRequestWithCancellationSource> pool;
|
static TaskPool<AssetBundleRequestWithCancellationSource> pool;
|
||||||
public AssetBundleRequestWithCancellationSource NextNode { get; set; }
|
AssetBundleRequestWithCancellationSource nextNode;
|
||||||
|
public ref AssetBundleRequestWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleRequestWithCancellationSource()
|
static AssetBundleRequestWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -799,7 +804,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
||||||
public AssetBundleRequestConfiguredSource NextNode { get; set; }
|
AssetBundleRequestConfiguredSource nextNode;
|
||||||
|
public ref AssetBundleRequestConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleRequestConfiguredSource()
|
static AssetBundleRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -981,7 +987,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleCreateRequestWithCancellationSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestWithCancellationSource>
|
sealed class AssetBundleCreateRequestWithCancellationSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleCreateRequestWithCancellationSource> pool;
|
static TaskPool<AssetBundleCreateRequestWithCancellationSource> pool;
|
||||||
public AssetBundleCreateRequestWithCancellationSource NextNode { get; set; }
|
AssetBundleCreateRequestWithCancellationSource nextNode;
|
||||||
|
public ref AssetBundleCreateRequestWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleCreateRequestWithCancellationSource()
|
static AssetBundleCreateRequestWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -1103,7 +1110,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
||||||
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
|
AssetBundleCreateRequestConfiguredSource nextNode;
|
||||||
|
public ref AssetBundleCreateRequestConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static AssetBundleCreateRequestConfiguredSource()
|
static AssetBundleCreateRequestConfiguredSource()
|
||||||
{
|
{
|
||||||
@@ -1307,7 +1315,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class UnityWebRequestAsyncOperationWithCancellationSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationWithCancellationSource>
|
sealed class UnityWebRequestAsyncOperationWithCancellationSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationWithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<UnityWebRequestAsyncOperationWithCancellationSource> pool;
|
static TaskPool<UnityWebRequestAsyncOperationWithCancellationSource> pool;
|
||||||
public UnityWebRequestAsyncOperationWithCancellationSource NextNode { get; set; }
|
UnityWebRequestAsyncOperationWithCancellationSource nextNode;
|
||||||
|
public ref UnityWebRequestAsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static UnityWebRequestAsyncOperationWithCancellationSource()
|
static UnityWebRequestAsyncOperationWithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -1438,7 +1447,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
||||||
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
|
UnityWebRequestAsyncOperationConfiguredSource nextNode;
|
||||||
|
public ref UnityWebRequestAsyncOperationConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static UnityWebRequestAsyncOperationConfiguredSource()
|
static UnityWebRequestAsyncOperationConfiguredSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class <#= t.typeName #>WithCancellationSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>WithCancellationSource>
|
sealed class <#= t.typeName #>WithCancellationSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>WithCancellationSource>
|
||||||
{
|
{
|
||||||
static TaskPool<<#= t.typeName #>WithCancellationSource> pool;
|
static TaskPool<<#= t.typeName #>WithCancellationSource> pool;
|
||||||
public <#= t.typeName #>WithCancellationSource NextNode { get; set; }
|
<#= t.typeName #>WithCancellationSource nextNode;
|
||||||
|
public ref <#= t.typeName #>WithCancellationSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static <#= t.typeName #>WithCancellationSource()
|
static <#= t.typeName #>WithCancellationSource()
|
||||||
{
|
{
|
||||||
@@ -297,7 +298,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
|
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<<#= t.typeName #>ConfiguredSource> pool;
|
static TaskPool<<#= t.typeName #>ConfiguredSource> pool;
|
||||||
public <#= t.typeName #>ConfiguredSource NextNode { get; set; }
|
<#= t.typeName #>ConfiguredSource nextNode;
|
||||||
|
public ref <#= t.typeName #>ConfiguredSource NextNode => ref nextNode;
|
||||||
|
|
||||||
static <#= t.typeName #>ConfiguredSource()
|
static <#= t.typeName #>ConfiguredSource()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"version": "2.0.28",
|
"version": "2.0.32",
|
||||||
"unity": "2018.4",
|
"unity": "2018.4",
|
||||||
"description": "Provides an efficient async/await integration to Unity.",
|
"description": "Provides an efficient async/await integration to Unity.",
|
||||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||||
|
|||||||
471
src/UniTask/Assets/Scenes/MiddlewareSample.cs
Normal file
471
src/UniTask/Assets/Scenes/MiddlewareSample.cs
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Sample
|
||||||
|
{
|
||||||
|
//public class Sample2
|
||||||
|
//{
|
||||||
|
// public Sample2()
|
||||||
|
// {
|
||||||
|
// // デコレーターの詰まったClientを生成(これは一度作ったらフィールドに保存可)
|
||||||
|
// var client = new NetworkClient("http://localhost", TimeSpan.FromSeconds(10),
|
||||||
|
// new QueueRequestDecorator(),
|
||||||
|
// new LoggingDecorator(),
|
||||||
|
// new AppendTokenDecorator(),
|
||||||
|
// new SetupHeaderDecorator());
|
||||||
|
|
||||||
|
|
||||||
|
// await client.PostAsync("/User/Register", new { Id = 100 });
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
public class ReturnToTitleDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await next(context, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException)
|
||||||
|
{
|
||||||
|
// キャンセルはきっと想定されている処理なのでそのまんまスルー(呼び出し側でOperationCanceledExceptionとして飛んでいく)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex is UnityWebRequestException uwe)
|
||||||
|
{
|
||||||
|
// ステータスコードを使って、タイトルに戻す例外です、とかリトライさせる例外です、とかハンドリングさせると便利
|
||||||
|
// if (uwe.ResponseCode) { }...
|
||||||
|
}
|
||||||
|
|
||||||
|
// サーバー例外のMessageを直接出すなんて乱暴なことはデバッグ時だけですよ勿論。
|
||||||
|
var result = await MessageDialog.ShowAsync(ex.Message);
|
||||||
|
|
||||||
|
// OK か Cancelかで分岐するなら。今回はボタン一個、OKのみの想定なので無視
|
||||||
|
// if (result == DialogResult.Ok) { }...
|
||||||
|
|
||||||
|
// シーン呼び出しはawaitしないこと!awaitして正常終了しちゃうと、この通信の呼び出し元に処理が戻って続行してしまいます
|
||||||
|
// のでForget。
|
||||||
|
SceneManager.LoadSceneAsync("TitleScene").ToUniTask().Forget();
|
||||||
|
|
||||||
|
|
||||||
|
// そしてOperationCanceledExceptionを投げて、この通信の呼び出し元の処理はキャンセル扱いにして終了させる
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DialogResult
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
Cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MessageDialog
|
||||||
|
{
|
||||||
|
public static async UniTask<DialogResult> ShowAsync(string message)
|
||||||
|
{
|
||||||
|
// (例えば)Prefabで作っておいたダイアログを生成する
|
||||||
|
var view = await Resources.LoadAsync("Prefabs/Dialog");
|
||||||
|
|
||||||
|
// Ok, Cancelボタンのどちらかが押されるのを待機
|
||||||
|
return await (view as GameObject).GetComponent<MessageDialogView>().ClickResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageDialogView : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] Button okButton = default;
|
||||||
|
[SerializeField] Button closeButton = default;
|
||||||
|
|
||||||
|
UniTaskCompletionSource<DialogResult> taskCompletion;
|
||||||
|
|
||||||
|
// これでどちらかが押されるまで無限に待つを表現
|
||||||
|
public UniTask<DialogResult> ClickResult => taskCompletion.Task;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
taskCompletion = new UniTaskCompletionSource<DialogResult>();
|
||||||
|
|
||||||
|
okButton.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
taskCompletion.TrySetResult(DialogResult.Ok);
|
||||||
|
});
|
||||||
|
|
||||||
|
closeButton.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
taskCompletion.TrySetResult(DialogResult.Cancel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// もしボタンが押されずに消滅した場合にネンノタメ。
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
taskCompletion.TrySetResult(DialogResult.Cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MockDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
Dictionary<string, object> mock;
|
||||||
|
|
||||||
|
// Pathと型を1:1にして事前定義したオブジェクトを返す辞書を渡す
|
||||||
|
public MockDecorator(Dictionary<string, object> mock)
|
||||||
|
{
|
||||||
|
this.mock = mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
if (mock.TryGetValue(context.Path, out var value))
|
||||||
|
{
|
||||||
|
// 一致したものがあればそれを返す(実際の通信は行わない)
|
||||||
|
return new UniTask<ResponseContext>(new ResponseContext(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return next(context, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LoggingDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Start Network Request:" + context.Path);
|
||||||
|
|
||||||
|
var response = await next(context, cancellationToken);
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log($"Complete Network Request: {context.Path} , Elapsed: {sw.Elapsed}, Size: {response.GetRawData().Length}");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Request Canceled:" + context.Path);
|
||||||
|
}
|
||||||
|
else if (ex is TimeoutException)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Request Timeout:" + context.Path);
|
||||||
|
}
|
||||||
|
else if (ex is UnityWebRequestException webex)
|
||||||
|
{
|
||||||
|
if (webex.IsHttpError)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log($"Request HttpError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}");
|
||||||
|
}
|
||||||
|
else if (webex.IsNetworkError)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log($"Request NetworkError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
/* log other */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetupHeaderDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
context.RequestHeaders["x-app-timestamp"] = context.Timestamp.ToString();
|
||||||
|
context.RequestHeaders["x-user-id"] = "132141411"; // どこかから持ってくる
|
||||||
|
context.RequestHeaders["x-access-token"] = "fafafawfafewaea"; // どこかから持ってくる2
|
||||||
|
|
||||||
|
var respsonse = await next(context, cancellationToken);
|
||||||
|
|
||||||
|
var nextToken = respsonse.ResponseHeaders["token"];
|
||||||
|
// UserProfile.Token = nextToken; // どこかにセットするということにする
|
||||||
|
|
||||||
|
return respsonse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class AppendTokenDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
string token = "token"; // どっかから取ってくるということにする
|
||||||
|
RETRY:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context.RequestHeaders["x-accesss-token"] = token;
|
||||||
|
return await next(context, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (UnityWebRequestException ex)
|
||||||
|
{
|
||||||
|
// 例えば700はTokenを再取得してください的な意味だったとする
|
||||||
|
if (ex.ResponseCode == 700)
|
||||||
|
{
|
||||||
|
// 別口でTokenを取得します的な処理
|
||||||
|
var newToken = await new NetworkClient(context.BasePath, context.Timeout).PostAsync<string>("/Auth/GetToken", "access_token", cancellationToken);
|
||||||
|
context.Reset(this);
|
||||||
|
goto RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto RETRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueueRequestDecorator : IAsyncDecorator
|
||||||
|
{
|
||||||
|
readonly Queue<(UniTaskCompletionSource<ResponseContext>, RequestContext, CancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>>)> q = new Queue<(UniTaskCompletionSource<ResponseContext>, RequestContext, CancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>>)>();
|
||||||
|
bool running;
|
||||||
|
|
||||||
|
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||||
|
{
|
||||||
|
if (q.Count == 0)
|
||||||
|
{
|
||||||
|
return await next(context, cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var completionSource = new UniTaskCompletionSource<ResponseContext>();
|
||||||
|
q.Enqueue((completionSource, context, cancellationToken, next));
|
||||||
|
if (!running)
|
||||||
|
{
|
||||||
|
Run().Forget();
|
||||||
|
}
|
||||||
|
return await completionSource.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid Run()
|
||||||
|
{
|
||||||
|
running = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (q.Count != 0)
|
||||||
|
{
|
||||||
|
var (tcs, context, cancellationToken, next) = q.Dequeue();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await next(context, cancellationToken);
|
||||||
|
tcs.TrySetResult(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.TrySetException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class RequestContext
|
||||||
|
{
|
||||||
|
int decoratorIndex;
|
||||||
|
readonly IAsyncDecorator[] decorators;
|
||||||
|
Dictionary<string, string> headers;
|
||||||
|
|
||||||
|
public string BasePath { get; }
|
||||||
|
public string Path { get; }
|
||||||
|
public object Value { get; }
|
||||||
|
public TimeSpan Timeout { get; }
|
||||||
|
public DateTimeOffset Timestamp { get; private set; }
|
||||||
|
|
||||||
|
public IDictionary<string, string> RequestHeaders
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (headers == null)
|
||||||
|
{
|
||||||
|
headers = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestContext(string basePath, string path, object value, TimeSpan timeout, IAsyncDecorator[] filters)
|
||||||
|
{
|
||||||
|
this.decoratorIndex = -1;
|
||||||
|
this.decorators = filters;
|
||||||
|
this.BasePath = basePath;
|
||||||
|
this.Path = path;
|
||||||
|
this.Value = value;
|
||||||
|
this.Timeout = timeout;
|
||||||
|
this.Timestamp = DateTimeOffset.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary<string, string> GetRawHeaders() => headers;
|
||||||
|
internal IAsyncDecorator GetNextDecorator() => decorators[++decoratorIndex];
|
||||||
|
|
||||||
|
public void Reset(IAsyncDecorator currentFilter)
|
||||||
|
{
|
||||||
|
decoratorIndex = Array.IndexOf(decorators, currentFilter);
|
||||||
|
if (headers != null)
|
||||||
|
{
|
||||||
|
headers.Clear();
|
||||||
|
}
|
||||||
|
Timestamp = DateTimeOffset.UtcNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResponseContext
|
||||||
|
{
|
||||||
|
bool hasValue;
|
||||||
|
object value;
|
||||||
|
readonly byte[] bytes;
|
||||||
|
|
||||||
|
public long StatusCode { get; }
|
||||||
|
public Dictionary<string, string> ResponseHeaders { get; }
|
||||||
|
|
||||||
|
public ResponseContext(object value, Dictionary<string, string> header = null)
|
||||||
|
{
|
||||||
|
this.hasValue = true;
|
||||||
|
this.value = value;
|
||||||
|
this.StatusCode = 200;
|
||||||
|
this.ResponseHeaders = (header ?? new Dictionary<string, string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseContext(byte[] bytes, long statusCode, Dictionary<string, string> responseHeaders)
|
||||||
|
{
|
||||||
|
this.hasValue = false;
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.StatusCode = statusCode;
|
||||||
|
this.ResponseHeaders = responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetRawData() => bytes;
|
||||||
|
|
||||||
|
public T GetResponseAs<T>()
|
||||||
|
{
|
||||||
|
if (hasValue)
|
||||||
|
{
|
||||||
|
return (T)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = JsonUtility.FromJson<T>(Encoding.UTF8.GetString(bytes));
|
||||||
|
hasValue = true;
|
||||||
|
return (T)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAsyncDecorator
|
||||||
|
{
|
||||||
|
UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class NetworkClient : IAsyncDecorator
|
||||||
|
{
|
||||||
|
readonly Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next;
|
||||||
|
readonly IAsyncDecorator[] decorators;
|
||||||
|
readonly TimeSpan timeout;
|
||||||
|
readonly IProgress<float> progress;
|
||||||
|
readonly string basePath;
|
||||||
|
|
||||||
|
public NetworkClient(string basePath, TimeSpan timeout, params IAsyncDecorator[] decorators)
|
||||||
|
: this(basePath, timeout, null, decorators)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkClient(string basePath, TimeSpan timeout, IProgress<float> progress, params IAsyncDecorator[] decorators)
|
||||||
|
{
|
||||||
|
this.next = InvokeRecursive; // setup delegate
|
||||||
|
|
||||||
|
this.basePath = basePath;
|
||||||
|
this.timeout = timeout;
|
||||||
|
this.progress = progress;
|
||||||
|
this.decorators = new IAsyncDecorator[decorators.Length + 1];
|
||||||
|
Array.Copy(decorators, this.decorators, decorators.Length);
|
||||||
|
this.decorators[this.decorators.Length - 1] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask<T> PostAsync<T>(string path, T value, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var request = new RequestContext(basePath, path, value, timeout, decorators);
|
||||||
|
var response = await InvokeRecursive(request, cancellationToken);
|
||||||
|
return response.GetResponseAs<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UniTask<ResponseContext> InvokeRecursive(RequestContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return context.GetNextDecorator().SendAsync(context, cancellationToken, next); // マジカル再帰処理
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTask<ResponseContext> IAsyncDecorator.SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> _)
|
||||||
|
{
|
||||||
|
// Postしか興味ないからPostにしかしないよ!
|
||||||
|
// パフォーマンスを最大限にしたい場合はuploadHandler, downloadHandlerをカスタマイズすること
|
||||||
|
|
||||||
|
// JSONでbodyに送るというパラメータで送るという雑設定。
|
||||||
|
var data = JsonUtility.ToJson(context.Value);
|
||||||
|
var formData = new Dictionary<string, string> { { "body", data } };
|
||||||
|
|
||||||
|
using (var req = UnityWebRequest.Post(basePath + context.Path, formData))
|
||||||
|
{
|
||||||
|
var header = context.GetRawHeaders();
|
||||||
|
if (header != null)
|
||||||
|
{
|
||||||
|
foreach (var item in header)
|
||||||
|
{
|
||||||
|
req.SetRequestHeader(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout処理はCancellationTokenSourceのCancelAfterSlim(UniTask拡張)を使ってサクッと処理
|
||||||
|
var linkToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||||
|
linkToken.CancelAfterSlim(timeout);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 完了待ちや終了処理はUniTaskの拡張自体に丸投げ
|
||||||
|
await req.SendWebRequest().ToUniTask(progress: progress, cancellationToken: linkToken.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// 元キャンセレーションソースがキャンセルしてなければTimeoutによるものと判定
|
||||||
|
if (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Timeoutに引っかからなかった場合にてるのでCancelAfterSlimの裏で回ってるループをこれで終わらせとく
|
||||||
|
if (!linkToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
linkToken.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnityWebRequestを先にDisposeしちゃうので先に必要なものを取得しておく(性能的には無駄なのでパフォーマンスを最大限にしたい場合は更に一工夫を)
|
||||||
|
return new ResponseContext(req.downloadHandler.data, req.responseCode, req.GetResponseHeaders());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/UniTask/Assets/Scenes/MiddlewareSample.cs.meta
Normal file
11
src/UniTask/Assets/Scenes/MiddlewareSample.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7fc39a4b35a8db44592cddc0b365942f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -17,6 +17,8 @@ using UnityEngine.UI;
|
|||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Cysharp.Threading.Tasks.Sample;
|
||||||
|
|
||||||
|
|
||||||
// using DG.Tweening;
|
// using DG.Tweening;
|
||||||
@@ -493,9 +495,11 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
RunStandardTaskAsync();
|
//Expression.Lambda<Func<int>>(null).Compile(true);
|
||||||
|
|
||||||
UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
//RunStandardTaskAsync();
|
||||||
|
|
||||||
|
//UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||||
|
|
||||||
//var url = "http://google.com/404";
|
//var url = "http://google.com/404";
|
||||||
//var webRequestAsyncOperation = UnityWebRequest.Get(url).SendWebRequest();
|
//var webRequestAsyncOperation = UnityWebRequest.Get(url).SendWebRequest();
|
||||||
@@ -524,8 +528,23 @@ public class SandboxMain : MonoBehaviour
|
|||||||
//UniTask.Delay(TimeSpan.FromSeconds(3)).
|
//UniTask.Delay(TimeSpan.FromSeconds(3)).
|
||||||
|
|
||||||
|
|
||||||
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
|
||||||
//{
|
|
||||||
|
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||||
|
{
|
||||||
|
|
||||||
|
var client = new NetworkClient("http://localhost:5000", TimeSpan.FromSeconds(2),
|
||||||
|
new QueueRequestDecorator(),
|
||||||
|
new LoggingDecorator());
|
||||||
|
//new AppendTokenDecorator(),
|
||||||
|
//new SetupHeaderDecorator());
|
||||||
|
|
||||||
|
|
||||||
|
await client.PostAsync("", new { Id = 100 });
|
||||||
|
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
// _ = ExecuteAsync();
|
// _ = ExecuteAsync();
|
||||||
|
|
||||||
// await UniTask.Yield();
|
// await UniTask.Yield();
|
||||||
|
|||||||
@@ -96,6 +96,33 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
// l[1].Item2.Should().NotBe(currentFrame);
|
// l[1].Item2.Should().NotBe(currentFrame);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator WaitForSecondsTest() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||||
|
|
||||||
|
Time.timeScale = 0.5f;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var now = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
await WaitFor();
|
||||||
|
|
||||||
|
var elapsed = DateTimeOffset.UtcNow - now;
|
||||||
|
|
||||||
|
(5.8f <= elapsed.TotalSeconds && elapsed.TotalSeconds <= 6.2f).Should().BeTrue();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Time.timeScale = 1.0f;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IEnumerator WaitFor()
|
||||||
|
{
|
||||||
|
yield return new WaitForSeconds(3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerator Worker(List<(int, int)> l)
|
IEnumerator Worker(List<(int, int)> l)
|
||||||
{
|
{
|
||||||
l.Add((0, Time.frameCount));
|
l.Add((0, Time.frameCount));
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ PlayerSettings:
|
|||||||
switchNVNShaderPoolsGranularity: 33554432
|
switchNVNShaderPoolsGranularity: 33554432
|
||||||
switchNVNDefaultPoolsGranularity: 16777216
|
switchNVNDefaultPoolsGranularity: 16777216
|
||||||
switchNVNOtherPoolsGranularity: 16777216
|
switchNVNOtherPoolsGranularity: 16777216
|
||||||
|
stadiaPresentMode: 0
|
||||||
|
stadiaTargetFramerate: 0
|
||||||
vulkanNumSwapchainBuffers: 3
|
vulkanNumSwapchainBuffers: 3
|
||||||
vulkanEnableSetSRGBWrite: 0
|
vulkanEnableSetSRGBWrite: 0
|
||||||
m_SupportedAspectRatios:
|
m_SupportedAspectRatios:
|
||||||
@@ -191,22 +193,6 @@ PlayerSettings:
|
|||||||
uIStatusBarHidden: 1
|
uIStatusBarHidden: 1
|
||||||
uIExitOnSuspend: 0
|
uIExitOnSuspend: 0
|
||||||
uIStatusBarStyle: 0
|
uIStatusBarStyle: 0
|
||||||
iPhoneSplashScreen: {fileID: 0}
|
|
||||||
iPhoneHighResSplashScreen: {fileID: 0}
|
|
||||||
iPhoneTallHighResSplashScreen: {fileID: 0}
|
|
||||||
iPhone47inSplashScreen: {fileID: 0}
|
|
||||||
iPhone55inPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPhone55inLandscapeSplashScreen: {fileID: 0}
|
|
||||||
iPhone58inPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPhone58inLandscapeSplashScreen: {fileID: 0}
|
|
||||||
iPadPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPadHighResPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPadLandscapeSplashScreen: {fileID: 0}
|
|
||||||
iPadHighResLandscapeSplashScreen: {fileID: 0}
|
|
||||||
iPhone65inPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPhone65inLandscapeSplashScreen: {fileID: 0}
|
|
||||||
iPhone61inPortraitSplashScreen: {fileID: 0}
|
|
||||||
iPhone61inLandscapeSplashScreen: {fileID: 0}
|
|
||||||
appleTVSplashScreen: {fileID: 0}
|
appleTVSplashScreen: {fileID: 0}
|
||||||
appleTVSplashScreen2x: {fileID: 0}
|
appleTVSplashScreen2x: {fileID: 0}
|
||||||
tvOSSmallIconLayers: []
|
tvOSSmallIconLayers: []
|
||||||
@@ -566,7 +552,8 @@ PlayerSettings:
|
|||||||
scriptingRuntimeVersion: 1
|
scriptingRuntimeVersion: 1
|
||||||
gcIncremental: 0
|
gcIncremental: 0
|
||||||
gcWBarrierValidation: 0
|
gcWBarrierValidation: 0
|
||||||
apiCompatibilityLevelPerPlatform: {}
|
apiCompatibilityLevelPerPlatform:
|
||||||
|
Standalone: 6
|
||||||
m_RenderingPath: 1
|
m_RenderingPath: 1
|
||||||
m_MobileRenderingPath: 1
|
m_MobileRenderingPath: 1
|
||||||
metroPackageName: Template_2D
|
metroPackageName: Template_2D
|
||||||
@@ -621,6 +608,7 @@ PlayerSettings:
|
|||||||
XboxOnePersistentLocalStorageSize: 0
|
XboxOnePersistentLocalStorageSize: 0
|
||||||
XboxOneXTitleMemory: 8
|
XboxOneXTitleMemory: 8
|
||||||
XboxOneOverrideIdentityName:
|
XboxOneOverrideIdentityName:
|
||||||
|
XboxOneOverrideIdentityPublisher:
|
||||||
vrEditorSettings:
|
vrEditorSettings:
|
||||||
daydream:
|
daydream:
|
||||||
daydreamIconForeground: {fileID: 0}
|
daydreamIconForeground: {fileID: 0}
|
||||||
|
|||||||
Reference in New Issue
Block a user