Compare commits

...

265 Commits

Author SHA1 Message Date
neuecc
a35e5f929d UNITASK_WEBREQUEST_SUPPORT 2021-02-08 19:09:02 +09:00
neuecc
9a3f10d4bf versionDefines for physics etc. 2021-02-08 18:08:56 +09:00
Yoshifumi Kawai
638522600a Merge pull request #220 from taigacon/master
Fix using AsyncUnityEventHandler with a already canceled token
2021-02-08 14:51:21 +09:00
Yoshifumi Kawai
081113a62c Merge pull request #224 from neilsarkar/master
Grammar edits for README.md
2021-02-08 14:01:03 +09:00
Yoshifumi Kawai
6d382450cf Merge pull request #226 from Cysharp/chore/release
chore: release on workflow_dispatch
2021-02-08 11:22:27 +09:00
Ikiru Yoshizaki
19f2a6f282 chore: pr build should run for master only 2021-02-04 03:01:21 +09:00
Ikiru Yoshizaki
7ed0b016ea chore: release on workflow_dispatch 2021-02-04 02:59:52 +09:00
Ikiru Yoshizaki
f72a51e13d chore: detect forgotten .meta file commit 2021-02-04 02:58:29 +09:00
Neil Sarkar
0e2dbbe754 Minor copyedit
`AsyncOpereationHandle<T>` -> `AsyncOperationHandle<T>`
2021-02-03 10:25:35 -05:00
Neil Sarkar
cff51a0425 Minor copyedit
oldest version -> lowest version
2021-02-03 10:18:32 -05:00
Neil Sarkar
7cac4bbbab Grammar fixes for README.md 2021-02-03 10:07:32 -05:00
taigacon
3f4a46bca6 Fix using AsyncUnityEventHandler with a already canceled token 2021-01-25 20:02:56 +08:00
neuecc
7d21a75ea8 2.1.1 2021-01-20 17:37:32 +09:00
neuecc
88817b7093 fix Coroutine.ToUniTask breaks pooling when coroutine return immediately 2021-01-20 17:31:55 +09:00
neuecc
52cdadc035 u 2021-01-07 17:43:35 +09:00
neuecc
5401b9b227 ready for release 2.1.0 2021-01-07 17:28:09 +09:00
neuecc
38de930f81 s 2021-01-07 17:25:03 +09:00
neuecc
9be6ef7ba6 new PlayerLoopType detector supports before 2019_4 2021-01-07 17:18:21 +09:00
neuecc
739bc6e26c add stale 2021-01-07 16:59:38 +09:00
neuecc
71879266ac Fix DelayType.Realtime does not work when use BuildPlayer in UnityEditor 2021-01-07 16:40:41 +09:00
neuecc
5ced0a1d4b Add UnityWebRequestException.ResponseHeaders #198 2021-01-07 16:03:27 +09:00
neuecc
908e361985 Add PlayerLoopTiming.TimeUpdate/LastTimeUpdate in Unity 2020.2 2021-01-07 13:02:18 +09:00
neuecc
797affae4d throw 2021-01-07 12:09:55 +09:00
Yoshifumi Kawai
ae3b825e29 Merge pull request #210 from WallyCZ/2020.2_fix
Unity 2020.2 changed order of the PlayerLoop subsystem list (should fix #208)
2021-01-07 12:01:11 +09:00
neuecc
143d97a73b update version 2021-01-07 11:59:31 +09:00
Václav Lipert
90631c54b1 More robust finding of right player loop system 2021-01-06 23:32:23 +01:00
Yoshifumi Kawai
478e2998a8 Merge pull request #204 from piti6/fix-defer
Accept calling DeferPromise.GetStatus multiple times
2021-01-06 17:45:28 +09:00
Yoshifumi Kawai
9406305b2e Merge pull request #203 from RamType0/FixCompletedTaskAsUniTaskAllocating
Suppress allocations around UniTask<T>.AsUniTask and UniTask.AsAsyncUnitUniTask
2021-01-06 17:19:19 +09:00
Václav Lipert
1c26c81b20 2020.2 changed PlayerLoopSystem order fix 2021-01-03 00:29:00 +01:00
RamType0
a455de88b0 Suppress allocations around UniTask<T>.AsUniTask and UniTask.AsAsyncUnitUniTask
- Fix completedTask.AsUniTask or completedTask.AsAsyncUnitUniTask leaks IUniTaskSource
- UniTask.AsAsyncUnitUniTask no longer allocates when its inner IUniTaskSource is IUniTaskSource<AsyncUnit>
2020-12-17 14:28:10 +09:00
piti6
fba6942d5f Accept GetStatus calling multiple times 2020-12-17 12:31:43 +09:00
Yoshifumi Kawai
3115efb672 Merge pull request #196 from RamType0/ForceCompleteJobHandleOnApplicationQuit
Force complete awaiting JobHandles when quitted in UnityEditor
2020-11-25 09:00:21 +09:00
Ram.Type-0
fd70c031cb Force complete awaiting JobHandles when quitted in UnityEditor 2020-11-24 23:50:01 +09:00
neuecc
a2eb75df68 Merge remote-tracking branch 'origin/master' 2020-11-09 16:08:20 +09:00
neuecc
4a62d7eba6 2.0.37 2020-11-09 16:08:17 +09:00
Yoshifumi Kawai
40d2d2fe06 Merge pull request #189 from IllusionCui/master
[DoTween]:fix CancellationToken can't stop UniTask
2020-11-09 15:52:13 +09:00
neuecc
d5d2cb5937 use Dictionary instead of ConcurrentDictionary for safety of WebGL build, #179 2020-11-09 14:34:11 +09:00
neuecc
854100c075 fix invalid usage of SpinLock, #195 2020-11-09 14:20:03 +09:00
cuibeibei
5837b26208 [DoTween]:fix CancellationToken can't stop UniTask 2020-10-28 18:48:10 +08:00
Yoshifumi Kawai
da0e654e7d Merge pull request #183 from Cysharp/chore/github_Actions_security_fix
chore: replace set-env to ENV FILE $GITHUB_ENV
2020-10-14 12:39:48 +09:00
Ikiru Yoshizaki
a3e9932be7 chore: replace set-env to ENV FILE $GITHUB_ENV
fix https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/
2020-10-14 12:12:28 +09:00
neuecc
e82353b4d9 UNITY_WEBGL unittest 2020-10-07 10:38:27 +09:00
Yoshifumi Kawai
944b61f28c Update README.md 2020-09-25 17:32:17 +09:00
Yoshifumi Kawai
457c574865 Update README.md 2020-09-24 10:31:59 +09:00
Yoshifumi Kawai
089a509663 Update README.md 2020-09-23 17:16:09 +09:00
neuecc
3bebaef969 2.0.36 2020-09-22 10:49:04 +09:00
neuecc
37e8b4500e Add enumerator.ToUniTask(MonoBehaviour coroutineRunner), log WARN on await enumerator when yield not supported types(Coroutine, WaitForEndOfFrame, WaitForFixedUpdate). 2020-09-22 10:08:03 +09:00
neuecc
8537ddf8a6 fix Forget when source is already completed and source is manualy optimized task source, does not work correctly 2020-09-22 09:54:05 +09:00
neuecc
346b1e0a6b 2.0.35 2020-09-21 12:56:13 +09:00
neuecc
fc7b9660a5 remove OnMouse_event trigger to prevent warning on Andoird, iOS, #170 2020-09-21 12:50:25 +09:00
neuecc
21e5cc22c7 notice for WaitForEndOfFrame #169 2020-09-21 12:49:26 +09:00
neuecc
3f18b37e5f changed clear loop runner queue timing in UnityEditor and run rest action when quitted 2020-09-21 12:30:31 +09:00
neuecc
5d4a90e9bd fix broken loop-runner from 2.0.32, #172 2020-09-21 11:42:02 +09:00
neuecc
2bf9f4f062 fix 2020-09-16 09:58:30 +09:00
neuecc
d69490cb49 one more things 2020-09-16 09:55:14 +09:00
neuecc
4e460c11ca 2.0.34 2020-09-16 09:48:57 +09:00
neuecc
9313969314 2.0.33 2020-09-15 06:53:58 +09:00
neuecc
a40f89a922 Merge remote-tracking branch 'origin/master' 2020-09-15 06:35:28 +09:00
neuecc
e0d8410b62 fix IEnumerator.ToUniTask, does not work correctly when coroutine complete immediately 2020-09-15 06:35:22 +09:00
Yoshifumi Kawai
bef1bd8ad1 Merge pull request #164 from c0nd3v/master
Fixed AwaitForAllAssets()
2020-09-12 06:09:29 +09:00
c0nd3v
81b4fcfac1 Fixed AwaitForAllAssets() 2020-09-11 10:41:41 -04:00
Yoshifumi Kawai
f1e4a3c65d Merge pull request #162 from hikarin522/patch-3
Fix UniTaskExtensions.Unwrap()
2020-09-09 15:38:03 +09:00
hikari
65622b01f6 [Unwrap] add ConfigureAwait 2020-09-09 14:15:03 +09:00
hikari
87dd5f13fd [Unwrap()] fix: remove type parameter 2020-09-09 14:05:37 +09:00
Yoshifumi Kawai
79cd2c17ba Update README.md 2020-09-07 18:55:44 +09:00
neuecc
85fb08552e Merge remote-tracking branch 'origin/master' 2020-09-07 18:52:22 +09:00
neuecc
7bd4b6faf7 2.0.32 2020-09-07 18:52:11 +09:00
neuecc
0b1ae7e295 docs: update TOC 2020-09-07 08:56:35 +00:00
neuecc
35a893ad9e Add UniTask.RunOnThreadPool 2020-09-07 17:56:02 +09:00
Yoshifumi Kawai
4955ed18f1 Merge pull request #157 from RamType-0/OptimizeConsumeEnumerator
Optimize EnumeratorPromise.ConsumeEnumerator while consuming CustomYieldInstruction
2020-09-07 17:23:08 +09:00
Yoshifumi Kawai
fe462328ab Merge pull request #148 from RamType-0/TaskPoolNodeByRef
Use ref T for ITaskPoolNode<T>.NextNode
2020-09-07 15:33:22 +09:00
Yoshifumi Kawai
5136d92efa Merge pull request #147 from RamType-0/OptimizeInternalContinuationIteration
Optimize ContinuationQueue and PlayerLoopRunner iteration
2020-09-07 15:32:50 +09:00
RamType0
227f7872cb Remove comments 2020-09-02 13:19:11 +09:00
Ram.Type-0
725b2fdc35 Format comment 2020-09-01 21:25:43 +09:00
Ram.Type-0
75abc8059f Optimize EnumeratorPromise.ConsumeEnumerator while consuming CustomYieldInstruction 2020-09-01 21:18:13 +09:00
RamType0
f1193743c8 Remove deprecated comment 2020-09-01 11:53:10 +09:00
Ram.Type-0
109730eacd Add missing migration from previous one 2020-08-30 14:18:55 +09:00
Ram.Type-0
1f736afe86 Revert change for ContinuationQueue.RunCore 2020-08-30 13:53:29 +09:00
Yoshifumi Kawai
4d554a6718 Merge pull request #149 from RamType-0/PlayerLoopRunnerInitializationFix
Fix PlayerLoopRunner at PlayerLoopTiming.Initialization is not assigned to PlayerLoopHelper.runners[0]
2020-08-30 09:49:19 +09:00
Ram.Type-0
69c0c362e9 Fix PlayerLoopRunner at PlayerLoopTiming.Initialization is not assigned to PlayerLoopHelper.runners[0] 2020-08-28 21:15:45 +09:00
RamType0
3bb446556a Use ref T for ITaskPoolNode<T>.NextNode 2020-08-28 18:03:22 +09:00
RamType0
ea950d8cec Optimize ContinuationQueue and PlayerLoopRunner iteration
- Fix failing to eliminate array bounds check in PlayerLoopRunner.RunCore
- Reduce number of array bounds check of continuation iteration in ContinuationQueue.RunCore
2020-08-28 17:12:03 +09:00
Yoshifumi Kawai
a65f4da7a2 Merge pull request #145 from RamType-0/TaskPoolNodeBenchmark
Add TaskPoolRefNode benchmark
2020-08-28 11:15:57 +09:00
Ram.Type-0
0bdc933c20 Add TaskPoolRefNode benchmark 2020-08-28 10:54:33 +09:00
Yoshifumi Kawai
0c0f79c6db Merge pull request #142 from hikarin522/patch-2
Add UniTaskExtensions.Unwrap()
2020-08-28 04:51:16 +09:00
hikari
32f9b9d4ac add Unwrap 2020-08-26 15:59:40 +09:00
neuecc
53907a3719 Merge remote-tracking branch 'origin/master' 2020-08-25 07:16:16 +09:00
neuecc
4937aeee3f 2.0.31 2020-08-25 07:16:08 +09:00
Yoshifumi Kawai
5e5b8aff89 Merge pull request #140 from hikarin522/patch-1
Fix ToCancellationToken
2020-08-25 07:13:56 +09:00
Yoshifumi Kawai
a2cbbd82d0 Merge pull request #139 from Cysharp/feature/SubscribeAwait
Add UniTaskAsyncEnumerable.SubscribeAwait
2020-08-25 07:12:00 +09:00
Yoshifumi Kawai
7eac5d8ba8 Merge pull request #138 from Cysharp/hotfix/ContinueOnErrorCallingOnNext
Continue to subscribe if an exception is raised when calling onNext
2020-08-25 07:11:43 +09:00
Yoshifumi Kawai
e2b1ed55ae Merge pull request #134 from SeungHuLee/Add-TMP-Generic-BindTo
Add TMP Generic BindTo Support
2020-08-25 07:11:26 +09:00
neuecc
727c7102d3 Add more DoTween support - AwaitForComplete, AwaitForPause, AwaitForPlay, AwaitForRewind, AwaitForStepComplete. 2020-08-25 07:10:39 +09:00
neuecc
1494ea6717 removelog spam on UniTaskAsyncEnumerable.EveryValueChanged #141 2020-08-25 06:43:31 +09:00
neuecc
f1ce64dbd3 middleware sample 2020-08-25 06:43:03 +09:00
hikari
3bad5cd2bf fixup! Fix ToCancellationToken linkToken 2020-08-25 02:55:09 +09:00
hikari
7432c0073a Fix ToCancellationToken linkToken 2020-08-24 17:10:26 +09:00
Mayuki Sawatari
f1813a7c94 Continue to subscribe if an exception is raised when calling onNext 2020-08-24 14:44:48 +09:00
Mayuki Sawatari
9e45c0a4d1 Add UniTaskAsyncEnumerable.SubscribeAwait 2020-08-24 14:35:20 +09:00
LSH
2c652cdde7 Add TMP Generic BindTo Support 2020-08-20 03:30:41 +09:00
neuecc
7718d345c8 2.0.30 2020-08-14 17:36:50 +09:00
neuecc
9f39708325 Merge remote-tracking branch 'origin/master' 2020-08-14 17:29:39 +09:00
neuecc
bb6dbfa920 Fix await IEnumerator + WaitForSeconds does not follow timescale(to behave same as StartCoroutine) #133 2020-08-14 17:29:30 +09:00
Yoshifumi Kawai
ba265005bb Merge pull request #132 from RamType-0/Disable-AutoReference-EditorAssembly
Disable "Auto Referenced" of UniTask.Editor
2020-08-14 06:25:21 +09:00
Ram.Type-0
4d7cc7ed61 Disable auto reference of UniTask.Editor 2020-08-14 04:56:58 +09:00
neuecc
b64f31eb0b 2.0.28 2020-08-13 17:44:15 +09:00
neuecc
38d159b69e IEnumerator.ToUniTask() behave same as StartCoroutine #120 2020-08-13 17:44:06 +09:00
neuecc
d5455f3716 Merge remote-tracking branch 'origin/master' 2020-08-13 16:33:41 +09:00
neuecc
a72ceeba11 UNITASK_ASSETBUNDLE_SUPPORT #131 2020-08-13 16:33:32 +09:00
Yoshifumi Kawai
c6b7d332b2 Update README.md 2020-08-12 11:41:21 +09:00
neuecc
f37278f2a6 docs: update TOC 2020-08-12 02:23:09 +00:00
Yoshifumi Kawai
3f3e03b83d Update README.md 2020-08-12 11:22:52 +09:00
Yoshifumi Kawai
c99d3eb3c3 Update README.md 2020-08-05 15:55:09 +09:00
Yoshifumi Kawai
08d5183e7e Merge pull request #121 from Cysharp/chore/unity_activation
chore: remove generate unity alf (activation license file)
2020-08-04 14:54:50 +09:00
Ikiru Yoshizaki
51769b2224 chore: remove generate unity alf (activation license file) 2020-08-04 13:20:33 +09:00
neuecc
6ec0ed8d61 docs: update TOC 2020-07-29 23:18:59 +00:00
neuecc
2e35324403 ready for 2.0.27 2020-07-30 08:12:32 +09:00
neuecc
e9474649c4 Add AssetBundleRequest.AwaitForAllAssets 2020-07-30 08:12:24 +09:00
neuecc
a8e0ce50c8 Fix Addressables async extensions when autoReleaseHandle: true 2020-07-30 08:12:03 +09:00
neuecc
db7ddba735 Add UniTaskSynchronizationContext, PlayerLoopHelper.IsInjectedUniTaskPlayerLoop, DumpCurrentPlayerLoop 2020-07-30 08:11:07 +09:00
neuecc
1999d94b33 Add UniTask.WithCancellation 2020-07-30 08:10:16 +09:00
neuecc
44af123b6c Update project version to 2019.4.5f1 2020-07-30 07:01:29 +09:00
neuecc
547b700ba7 AsyncOperation/Addressables returns Cacnceled UniTask when already canceled. 2020-07-16 06:12:39 +09:00
neuecc
6b87d5d2b0 2.0.26 2020-07-16 06:05:04 +09:00
neuecc
023894d45e Merge remote-tracking branch 'origin/master' 2020-07-16 05:37:08 +09:00
Yoshifumi Kawai
009715c0da Merge pull request #115 from IllusionCui/master
[addressable]:fix CancellationToken can't stop UniTask #114
2020-07-16 05:37:01 +09:00
neuecc
c2824027d4 more strict handle cancel timing on asyncOperation.WithCancellation() 2020-07-16 05:36:21 +09:00
cuibeibei
65b6553a1a [addressable]:fix CancellationToken can't stop UniTask #114 2020-07-15 15:14:08 +08:00
neuecc
9d3b7adc8e Add CancellationToken cancellationToken = default to UniTask.Run #113 2020-07-14 11:25:30 +09:00
neuecc
3724fc204c memo of IL2CPP VM bug. 2020-07-14 06:40:32 +09:00
neuecc
b97451a915 UnityWebRequest, Addressables returns exception when already isDone and AsyncOperation has error. 2020-07-13 09:34:43 +09:00
neuecc
9ddcac4c6c ignore1 2020-07-13 01:00:16 +09:00
neuecc
b61e3c347f remove unity csproj 2020-07-11 02:19:40 +09:00
neuecc
0bb44066c0 2.0.25 2020-07-09 22:39:48 +09:00
neuecc
305c4aaa07 fix UnityWebRequestException String access is not supported #110 2020-07-09 22:17:49 +09:00
neuecc
42d627f3ba fix again #108 2020-07-09 17:29:04 +09:00
neuecc
6dd2b464a3 NRE on head request with invalid url #108 2020-07-09 01:31:27 +09:00
neuecc
32f24cf8f8 cleanup unused code 2020-07-04 22:08:48 +09:00
neuecc
4a89e3ea86 r 2020-07-04 06:44:57 +09:00
neuecc
887db5b281 2.0.24 2020-07-04 06:36:14 +09:00
neuecc
fee5518a82 Improve, Select/Where add UniTaskTracker 2020-07-04 06:29:50 +09:00
neuecc
551128e64c Add UniTaskAsyncEnumerable.Create 2020-07-04 06:29:33 +09:00
neuecc
c65ae8d18e error detail 2020-07-04 06:29:08 +09:00
neuecc
c1f75d9ebd Add UniTask.Never 2020-06-30 04:01:00 +09:00
neuecc
73a5ff6648 r 2020-06-29 03:24:10 +09:00
neuecc
1c264f380e 2.0.23 2020-06-29 03:22:33 +09:00
neuecc
f02bfa0a1e Fix lose exception stacktrace info when task is sync completed 2020-06-29 03:20:13 +09:00
neuecc
9d684006fc test 2020-06-29 03:02:23 +09:00
neuecc
c49f1ed028 r 2020-06-29 01:18:16 +09:00
neuecc
d935b226c0 2.0.22 2020-06-29 01:13:37 +09:00
neuecc
d9e20de8a5 Add UniTaskAsyncEnumerable.SkipUntil, TakeUntil. Fix SkipUntilCanceled behaviour. 2020-06-29 01:10:18 +09:00
neuecc
23997f0f93 SwitchToMainThread, ReturnToMainThread, SwitchToSynchronizationContext, ReturnToSynchronizationContext supports CancellationToken 2020-06-28 20:57:42 +09:00
neuecc
529272d11b more ignore 2020-06-28 18:01:01 +09:00
neuecc
1194c38568 Add AsyncGPUReadbackRequest await support 2020-06-28 17:59:03 +09:00
neuecc
f0d2ee2beb typo 2020-06-26 17:57:27 +09:00
neuecc
68cdda086a async UniTaskVoid Start 2020-06-26 17:53:07 +09:00
neuecc
54ceca6ceb R 2020-06-25 23:03:13 +09:00
neuecc
50bdf7460c 2.0.21 2020-06-25 23:02:40 +09:00
neuecc
c06e45d0bb ToCancellationToken(linkeToken) 2020-06-25 23:02:30 +09:00
neuecc
3ed6e28a00 Removed Timeout(bool ignoreTimeScale), changed to Timeout(DelayType delayType) 2020-06-25 22:35:55 +09:00
neuecc
ab76098895 Removed CancelAfterSlim(bool ignoreTimeScale), changed to CancelAfterSlim(DelayType delayType) 2020-06-25 22:35:35 +09:00
neuecc
0a447e43b0 Add UniTask.ToCancellationToken 2020-06-25 22:34:45 +09:00
neuecc
8df44f2768 Remove UniTask.DelayRealtime, Add UniTask.Delay(DelayType) overload 2020-06-25 22:15:44 +09:00
neuecc
a7ec64d644 more 20 2020-06-24 05:09:00 +09:00
neuecc
868e104d85 2.0.20 2020-06-24 05:04:18 +09:00
neuecc
7ced7f5764 separate external assemblies, add TMP_InputField extensions 2020-06-24 05:04:09 +09:00
neuecc
12b39c6ba1 Add UniTask.DelayRealtime 2020-06-24 01:40:43 +09:00
neuecc
93df9d7693 Prevent -> Preserve in ReadMe 2020-06-21 23:11:47 +09:00
neuecc
3980f314fa Fix UnityWebRequestExtensions obsolete warning in Unity 2020.2 2020-06-19 16:46:30 +09:00
neuecc
c2538da1cd Improve UnityWebRequestError performance 2020-06-19 16:45:55 +09:00
neuecc
5ed943bca2 Add UniTask.Post 2020-06-19 16:42:05 +09:00
neuecc
d6a0563319 ready 2.0.19 2020-06-18 03:39:44 +09:00
neuecc
af82a94b87 Fix TimeoutWithoutException does not suppress exception 2020-06-18 03:30:53 +09:00
neuecc
82219e6111 Fix UniTask.Delay does not run on threadpool thread 2020-06-18 03:28:03 +09:00
neuecc
81f9c55c7f Add UniTask.Run(Func<UniTask>) overload 2020-06-18 03:27:26 +09:00
neuecc
0640f278cc Fix AsyncLazy can not await multiple times when task is not completed 2020-06-18 03:02:01 +09:00
neuecc
769b5c6bab UniTaskCompletionSource can await multiple times(same behaviour as TaskCompletionSource) 2020-06-18 02:34:56 +09:00
neuecc
bdd569e213 fix can not close application in mono build 2020-06-17 21:37:45 +09:00
neuecc
5bfff5bc24 Subscribe ReadMe 2020-06-15 22:46:01 +09:00
neuecc
edf32496e4 re 2020-06-15 15:29:12 +09:00
neuecc
785f5837d1 Merge remote-tracking branch 'origin/master' 2020-06-15 15:28:29 +09:00
neuecc
8c9272bc9f 2.0.18 2020-06-15 15:26:28 +09:00
neuecc
3e00735b3d Add AsUniTaskAsyncEnumerable/AsAsyncEnumerable in .NET Core 2020-06-15 15:23:25 +09:00
neuecc
00a1be8666 await UnityWebRequestAsyncOperation throws UnityWebRequestException when isHttpError or isNetworkError 2020-06-15 15:23:07 +09:00
neuecc
a2783d3c8a yes meta 2020-06-15 12:29:46 +09:00
Yoshifumi Kawai
85d1a8a4a4 Update README.md 2020-06-14 15:44:40 +09:00
neuecc
bbfb8354bb 2.0.17 2020-06-14 15:32:37 +09:00
Yoshifumi Kawai
2f68e47443 Merge pull request #92 from yashihei/fix-cancellation-token
Fixed CancelationToken not being passed correctly
2020-06-14 15:08:37 +09:00
yashihei
89339ffb29 Fixed CancelationToken not being passed correctly 2020-06-14 08:24:25 +09:00
neuecc
0535862fe6 Merge remote-tracking branch 'origin/master' 2020-06-13 18:58:56 +09:00
neuecc
a9e5fd4589 Add UniTaskAsyncEnumerable.Subscribe 2020-06-13 18:58:43 +09:00
Yoshifumi Kawai
a3f3a28ea1 Update README.md 2020-06-12 17:18:31 +09:00
Yoshifumi Kawai
59020df965 Update README.md 2020-06-12 17:18:22 +09:00
Yoshifumi Kawai
ac01be79bf Update README.md 2020-06-12 16:59:14 +09:00
neuecc
de5951f208 lock q 2020-06-12 10:46:29 +09:00
neuecc
ded9a561db 2.0.16 2020-06-12 03:16:06 +09:00
neuecc
a2c18eb343 AsyncReactiveProperty document 2020-06-11 23:50:13 +09:00
neuecc
0b27c3a342 Merge remote-tracking branch 'origin/master' 2020-06-11 23:32:00 +09:00
neuecc
9c86cfb508 Add IDisposable.AddTo(cancellationToken) 2020-06-11 23:31:55 +09:00
Yoshifumi Kawai
7e5e6ed6c2 Update README.md 2020-06-11 20:21:51 +09:00
Yoshifumi Kawai
d081e5f40b Update README.md 2020-06-11 17:48:41 +09:00
neuecc
344ae0738c docs: update TOC 2020-06-11 08:44:42 +00:00
neuecc
1b553f67b0 compare table 2020-06-11 17:44:22 +09:00
neuecc
bf0adad427 test for IL2CPP bug 2020-06-11 17:10:29 +09:00
neuecc
11ca42a527 Merge remote-tracking branch 'origin/master' 2020-06-11 16:43:11 +09:00
neuecc
4898e4c7bf Add (I/ReadOnly)AsyncReactiveProperty.WaitAsync 2020-06-11 16:42:59 +09:00
Yoshifumi Kawai
d494e0b9e3 Merge pull request #88 from guitarrapc/master
chore: stop run build-unity via fork PR
2020-06-11 14:35:12 +09:00
Ikiru Yoshizaki
be26ab249b chore: strict filter 2020-06-10 18:17:53 +09:00
Ikiru Yoshizaki
611d8d5513 chore: filter build-unity to be run on Cysharp only 2020-06-10 18:06:50 +09:00
Yoshifumi Kawai
95c93b7c3d Merge pull request #87 from guitarrapc/master
feat: Android il2cpp support
2020-06-10 17:07:56 +09:00
Ikiru Yoshizaki
1dd0c49eec faet: android il2cpp 2020-06-10 13:06:45 +09:00
neuecc
5d8e0e61ad workaround for IL2CPP bug, back to zero allocation 2020-06-10 11:36:58 +09:00
neuecc
478126e256 v 2020-06-09 15:06:34 +09:00
neuecc
80704e489d Merge branch 'fix-il2cpp' 2020-06-09 14:52:23 +09:00
neuecc
3c0aa03643 if def 2020-06-09 14:52:04 +09:00
neuecc
37cd00d347 2.0.15? 2020-06-09 12:16:28 +09:00
neuecc
859c4d706f logging 2020-06-09 12:00:12 +09:00
neuecc
7289fe6e25 ToCoroutine throws exception when error detected 2020-06-09 11:26:03 +09:00
neuecc
0c33977f5a timer and delay skip current frame 2020-06-09 11:25:45 +09:00
neuecc
4d4466e801 Add UniTask.WaitForFixedUpdate 2020-06-08 02:22:10 +09:00
neuecc
79330d7cdb ReadMe 2020-06-08 01:50:20 +09:00
neuecc
680ce1098b ReadMe 2020-06-08 01:45:57 +09:00
neuecc
2337d705ec WithCancellation uses native timing of asyncOperation 2020-06-08 01:45:41 +09:00
neuecc
d2880a818f Add UniTask.NextFrame, UniTask.WaitForEndOfFrame 2020-06-08 01:44:31 +09:00
neuecc
86ea128bf4 t4gen 2020-06-08 00:30:27 +09:00
neuecc
a66f378622 // for CI 2020-06-07 00:27:33 +09:00
neuecc
265f88584b store application.datapath on initialize #86 2020-06-06 14:21:31 +09:00
neuecc
686394c861 2.0.14 pkg version 2020-06-05 17:16:34 +09:00
neuecc
8bad158ab4 fix ci 2020-06-05 17:05:36 +09:00
neuecc
5e59e7ec86 netstandard2.0 support #84 2020-06-05 16:45:40 +09:00
neuecc
8bb0a48720 workaround for struct enumerator await 2020-06-05 15:08:13 +09:00
neuecc
b4468b4eba improve DOTween Extensions 2020-06-05 12:32:16 +09:00
neuecc
0725bd1b30 Merge remote-tracking branch 'origin/master' 2020-06-05 00:44:16 +09:00
neuecc
ebd80243e0 Fix UniTask.ReturnToCurrentSynchronizationContext 2020-06-05 00:43:54 +09:00
neuecc
f1ac469058 Fix UniTask.Defer 2020-06-05 00:43:03 +09:00
neuecc
2e0b603d25 docs: update TOC 2020-06-04 08:54:24 +00:00
neuecc
1d90a40f66 more ReadMe 2020-06-04 17:53:57 +09:00
Mayuki Sawatari
1bec3f507e Merge pull request #75 from Cysharp/feature/docs
Generate and publish documentation to GitHub Pages
2020-06-04 16:16:03 +09:00
Mayuki Sawatari
1d5ecbb3ab Include sub-directory source codes 2020-06-04 15:46:21 +09:00
Mayuki Sawatari
e1a4aeb9da Update toc.yml 2020-06-04 15:46:21 +09:00
Mayuki Sawatari
43f1bb4d85 Generate and publish documentation to GitHub Pages 2020-06-04 15:46:21 +09:00
Yoshifumi Kawai
8b7a0e9b15 Update README.md 2020-06-04 15:31:42 +09:00
neuecc
da329e19d1 CI more 2020-06-04 15:24:09 +09:00
Yoshifumi Kawai
b8260d4e91 Merge pull request #61 from Cysharp/unitask2
UniTask2
2020-06-04 15:17:19 +09:00
neuecc
345e32aaf0 CI again 2020-06-04 15:14:40 +09:00
neuecc
d7bef8c5b5 setup release 2020-06-04 15:11:51 +09:00
neuecc
b2f82df4d3 fix action 2020-06-04 14:58:11 +09:00
neuecc
83596b3d1f docs: update TOC 2020-06-04 05:53:07 +00:00
neuecc
0022598a1c readme 2020-06-04 14:52:42 +09:00
neuecc
f4294d3752 Task Pool moved from Internal 2020-06-04 14:52:36 +09:00
neuecc
a1444c0b39 refactor DistinctUntilChanged 2020-06-03 02:03:31 +09:00
neuecc
e1d5359d73 refactor Where 2020-06-03 01:18:39 +09:00
neuecc
239bf749b6 refactor UniTaskAsyncEnumerable.Select 2020-06-03 00:50:39 +09:00
neuecc
2bf3b1e172 pj 2020-06-02 23:27:42 +09:00
neuecc
d225de201f gitignore 2020-06-02 23:00:47 +09:00
neuecc
c3b8a3852d UniTask.Linq.asmdef 2020-06-02 23:00:20 +09:00
neuecc
c31dab888e fix UnITaskTracker causes Stackoverflow 2020-06-02 22:49:40 +09:00
neuecc
d4cf59bd2f CI 2020-06-01 14:50:25 +09:00
neuecc
d5edc3acd3 guard for trigger invalid ops 2020-06-01 13:51:37 +09:00
neuecc
130286e8c2 TriggerEvent becomes linkedlist 2020-06-01 13:40:35 +09:00
neuecc
a9baa52309 Add ReturnToMainThread, ReturnToSynchronizationContext, ReturnToCurrentSynchronizationContext 2020-05-31 04:30:03 +09:00
neuecc
3001996298 Q check 2020-05-31 04:28:05 +09:00
neuecc
bfcd18aabb MoveNextRunner -> StateMachineRunner 2020-05-29 14:35:50 +09:00
neuecc
96aa299e7e support version -> unity 2018.4 2020-05-29 14:25:26 +09:00
neuecc
24faa34418 TaskPoolMonitor -> TaskPool 2020-05-29 03:58:22 +09:00
161 changed files with 16156 additions and 2823 deletions

View File

@@ -3,16 +3,16 @@ name: Build-Debug
on: on:
push: push:
branches: branches:
- "**" - "master"
tags: tags:
- "!*" # not a tag push - "!*" # not a tag push
pull_request: pull_request:
types: branches:
- opened - "master"
- synchronize
jobs: jobs:
build-dotnet: build-dotnet:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1
@@ -22,13 +22,14 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 3.1.101 dotnet-version: 3.1.x
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj - run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
build-unity: build-unity:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]')) && ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
strategy: strategy:
matrix: matrix:
unity: ['2019.3.9f1', '2020.1.0b5'] unity: ["2019.3.9f1", "2020.1.0b5"]
include: include:
- unity: 2019.3.9f1 - unity: 2019.3.9f1
license: UNITY_2019_3 license: UNITY_2019_3
@@ -39,15 +40,11 @@ jobs:
# with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags # with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags
image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp
steps: steps:
- run: apt update && apt install git -y # Ubuntu 18.04 git is too old, use ppa latest git.
- run: |
apt-get update && apt-get install --no-install-recommends -y software-properties-common && add-apt-repository -y ppa:git-core/ppa
apt-get update && apt-get install --no-install-recommends -y git
- uses: actions/checkout@v2 - uses: actions/checkout@v2
# create unity activation file and store to artifacts.
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile || exit 0
- uses: actions/upload-artifact@v1
with:
name: Unity_v${{ matrix.unity }}.alf
path: ./Unity_v${{ matrix.unity }}.alf
# activate Unity from manual license file(ulf)
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf - run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
env: env:
UNITY_LICENSE: ${{ secrets[matrix.license] }} UNITY_LICENSE: ${{ secrets[matrix.license] }}
@@ -66,8 +63,18 @@ jobs:
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
working-directory: src/UniTask working-directory: src/UniTask
# Store artifacts. - name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
# Store artifacts.
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
name: UniTask.unitypackage.zip name: UniTask.unitypackage.zip
path: ./src/UniTask/*.unitypackage path: ./src/UniTask/*.unitypackage

31
.github/workflows/build-docs.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: build-docs
on:
push:
branches:
- master
- feature/docs
jobs:
run-docfx:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
repository: Cysharp/DocfxTemplate
path: docs/_DocfxTemplate
- uses: Kirbyrawr/docfx-action@master
name: Docfx metadata
with:
args: metadata docs/docfx.json
- uses: Kirbyrawr/docfx-action@master
name: Docfx build
with:
args: build docs/docfx.json
- name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/_site

View File

@@ -1,108 +1,185 @@
name: Build-Release name: build-release
on: on:
push: workflow_dispatch:
tags: inputs:
- "[0-9]+.[0-9]+.[0-9]+*" tag:
description: "tag: git tag you want create. (sample 1.0.0)"
required: true
dry_run:
description: "dry_run: true will never create relase/nuget."
required: true
default: "false"
env:
GIT_TAG: ${{ github.event.inputs.tag }}
DRY_RUN: ${{ github.event.inputs.dry_run }}
DRY_RUN_BRANCH_PREFIX: "test_release"
DOTNET_SDK_VERISON_3: 3.1.x
jobs: jobs:
build-dotnet: update-packagejson:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
TARGET_FILE: ./src/UniTask/Assets/Plugins/UniTask/package.json
outputs:
sha: ${{ steps.commit.outputs.sha }}
steps:
- uses: actions/checkout@v2
- name: before
run: cat ${{ env.TARGET_FILE}}
- name: update package.json to version ${{ env.GIT_TAG }}
run: sed -i -e "s/\(\"version\":\) \"\(.*\)\",/\1 \"${{ env.GIT_TAG }}\",/" ${{ env.TARGET_FILE }}
- name: after
run: cat ${{ env.TARGET_FILE}}
- name: Commit files
id: commit
run: |
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "feat: Update package.json to ${{ env.GIT_TAG }}" -a
echo "::set-output name=sha::$(git rev-parse HEAD)"
- name: check sha
run: echo "SHA ${SHA}"
env:
SHA: ${{ steps.commit.outputs.sha }}
- name: tag
run: git tag ${{ env.GIT_TAG }}
if: env.DRY_RUN == 'false'
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
tags: true
if: env.DRY_RUN == 'false'
- name: Push changes (dry_run)
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
tags: false
if: env.DRY_RUN == 'true'
build-dotnet:
needs: [update-packagejson]
runs-on: ubuntu-latest
timeout-minutes: 10
env: env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip NUGET_XMLDOC_MODE: skip
steps: steps:
- run: echo ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 3.1.101 dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
# set release tag(*.*.*) to env.GIT_TAG # build and pack
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/}
# build CommandTools first (use dotnet run command in ZLogger.csproj)
- run: dotnet build -c Release ./tools/CommandTools/CommandTools.csproj
- run: dotnet build -c Release -p:Version=${{ env.GIT_TAG }} - run: dotnet build -c Release -p:Version=${{ env.GIT_TAG }}
- run: dotnet test -c Release --no-build - run: dotnet test -c Release --no-build
- run: dotnet pack ./src/ZLogger/ZLogger.csproj -c Release --no-build -p:Version=${{ env.GIT_TAG }} - run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ env.GIT_TAG }} -o ./publish
# Store artifacts. # Store artifacts.
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:
name: nuget name: nuget
path: ./src/ZLogger/bin/Release/ZLogger.${{ env.GIT_TAG }}.nupkg path: ./publish/
build-unity: build-unity:
needs: [update-packagejson]
strategy: strategy:
matrix: matrix:
unity: ['2019.3.9f1'] unity: ["2019.3.9f1"]
include: include:
- unity: 2019.3.9f1 - unity: 2019.3.9f1
license: UNITY_2019_3 license: UNITY_2019_3
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 15
container: container:
# with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags # with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags
image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp
steps: steps:
- run: apt update && apt install git -y # Ubuntu 18.04 git is too old, use ppa latest git.
- run: |
apt-get update && apt-get install --no-install-recommends -y software-properties-common && add-apt-repository -y ppa:git-core/ppa
apt-get update && apt-get install --no-install-recommends -y git
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
# activate Unity from manual license file(ulf)
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf - run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
env: env:
UNITY_LICENSE: ${{ secrets[matrix.license] }} UNITY_LICENSE: ${{ secrets[matrix.license] }}
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -manualLicenseFile .Unity.ulf || exit 0 - run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -manualLicenseFile .Unity.ulf || exit 0
# set release tag(*.*.*) to env.GIT_TAG
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/}
# Execute scripts: Export Package # Execute scripts: Export Package
- name: Export unitypackage - name: Export unitypackage
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
working-directory: src/ZLogger.Unity working-directory: src/UniTask
env:
UNITY_PACKAGE_VERSION: ${{ env.GIT_TAG }} - name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
# Store artifacts. # Store artifacts.
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v2
with: with:
name: ZLogger.Unity.${{ env.GIT_TAG }}.unitypackage name: UniTask.${{ env.GIT_TAG }}.unitypackage
path: ./src/ZLogger.Unity/ZLogger.Unity.${{ env.GIT_TAG }}.unitypackage path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
create-release: create-release:
needs: [build-dotnet, build-unity] if: github.event.inputs.dry_run == 'false'
needs: [update-packagejson, build-dotnet, build-unity]
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip NUGET_XMLDOC_MODE: skip
steps: steps:
# setup dotnet for nuget push # setup dotnet for nuget push
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 3.1.101 dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
# set release tag(*.*.*) to env.GIT_TAG # Create Releases
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/} - uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.GIT_TAG }}
release_name: Ver.${{ env.GIT_TAG }}
commitish: ${{ needs.update-packagejson.outputs.sha }}
draft: true
prerelease: false
# Download(All) Artifacts to current directory
- uses: actions/download-artifact@v2
# Upload to NuGet
- run: dotnet nuget push "./nuget/*.nupkg" --skip-duplicate -s https://www.nuget.org/api/v2/package -k ${{ secrets.NUGET_KEY }}
# Upload to Releases(unitypackage)
- uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./UniTask.${{ env.GIT_TAG }}.unitypackage/UniTask.${{ env.GIT_TAG }}.unitypackage
asset_name: UniTask.${{ env.GIT_TAG }}.unitypackage
asset_content_type: application/octet-stream
# Create Releases cleanup:
- uses: actions/create-release@v1 if: github.event.inputs.dry_run == 'true'
id: create_release needs: [build-dotnet, build-unity]
env: runs-on: ubuntu-latest
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps:
with: - name: Delete branch
tag_name: ${{ github.ref }} uses: dawidd6/action-delete-branch@v3
release_name: Ver.${{ github.ref }} with:
github_token: ${{ github.token }}
# Download (All) Artifacts to current directory branches: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
- uses: actions/download-artifact@v2-preview
# Upload to NuGet
- run: dotnet nuget push "./nuget/*.nupkg" -s https://www.nuget.org/api/v2/package -k ${{ secrets.NUGET_KEY }}
# Upload to Releases(unitypackage)
- uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./ZLogger.Unity.${{ env.GIT_TAG }}.unitypackage/ZLogger.Unity.${{ env.GIT_TAG }}.unitypackage
asset_name: ZLogger.Unity.${{ env.GIT_TAG }}.unitypackage
asset_content_type: application/octet-stream

24
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: "Close stale issues"
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# enable issue
stale-issue-message: "This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
stale-issue-label: "stale"
# enable pr
stale-pr-message: "This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
stale-pr-label: "stale"
days-before-stale: 90
days-before-close: 7
exempt-issue-labels: "wip"
exempt-pr-labels: "wip"
remove-stale-when-updated: true

102
.gitignore vendored
View File

@@ -157,3 +157,105 @@ src/UniTask/UniTask.Tests.csproj
src/UniTask/UniTask.Tests.Editor.csproj src/UniTask/UniTask.Tests.Editor.csproj
src/UniTask/UniTask.*.unitypackage src/UniTask/UniTask.*.unitypackage
src/UniTask/UniTask.Linq.csproj
src/UniTask/DOTween.Modules.csproj
src/UniTask/Unity.Addressables.csproj
src/UniTask/Unity.Addressables.Editor.csproj
src/UniTask/Unity.Analytics.DataPrivacy.csproj
src/UniTask/Unity.Recorder.csproj
src/UniTask/Unity.Recorder.Editor.csproj
src/UniTask/Unity.ResourceManager.csproj
src/UniTask/Unity.Rider.Editor.csproj
src/UniTask/Unity.ScriptableBuildPipeline.csproj
src/UniTask/Unity.ScriptableBuildPipeline.Editor.csproj
src/UniTask/Unity.TextMeshPro.csproj
src/UniTask/Unity.TextMeshPro.Editor.csproj
src/UniTask/Unity.Timeline.csproj
src/UniTask/Unity.Timeline.Editor.csproj
src/UniTask/Unity.VisualStudio.Editor.csproj
src/UniTask/Unity.VSCode.Editor.csproj
src/UniTask/UnityEditor.CacheServer.csproj
src/UniTask/UnityEditor.TestRunner.csproj
src/UniTask/UnityEditor.UI.csproj
src/UniTask/UnityEngine.Advertisements.csproj
src/UniTask/UnityEngine.Monetization.csproj
src/UniTask/UnityEngine.TestRunner.csproj
src/UniTask/UnityEngine.UI.csproj
src/UniTask/TempAsm.csproj
src/UniTask/UniTask.Addressables.csproj
src/UniTask/UniTask.DOTween.csproj
src/UniTask/UniTask.TextMeshPro.csproj
src/UniTask/RuntimeUnitTestToolkit.Player.csproj
src/UniTask/TempAsm.Player.csproj
src/UniTask/UniTask.Addressables.Player.csproj
src/UniTask/UniTask.DOTween.Player.csproj
src/UniTask/UniTask.Linq.Player.csproj
src/UniTask/UniTask.Player.csproj
src/UniTask/UniTask.Tests.Player.csproj
src/UniTask/UniTask.TextMeshPro.Player.csproj
src/UniTask/Unity.Addressables.Player.csproj
src/UniTask/Unity.Analytics.DataPrivacy.Player.csproj
src/UniTask/Unity.ResourceManager.Player.csproj
src/UniTask/Unity.ScriptableBuildPipeline.Player.csproj
src/UniTask/Unity.TextMeshPro.Player.csproj
src/UniTask/Unity.Timeline.Player.csproj
src/UniTask/UnityEngine.Advertisements.Player.csproj
src/UniTask/UnityEngine.Monetization.Player.csproj
src/UniTask/UnityEngine.TestRunner.Player.csproj
src/UniTask/UnityEngine.UI.Player.csproj
src/UniTask/DOTween.Modules.Player.csproj
src/UniTask/Assembly-CSharp.Player.csproj
src/UniTask/Unity.EditorCoroutines.Editor.csproj
src/UniTask/.vsconfig
src/UniTask/Logs/ApiUpdaterCheck.txt

834
README.md

File diff suppressed because it is too large Load Diff

10
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
###############
# folder #
###############
/**/DROP/
/**/TEMP/
/**/packages/
/**/bin/
/**/obj/
_site
_DocfxTemplate

5
docs/api/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
###############
# temp file #
###############
*.yml
.manifest

70
docs/docfx.json Normal file
View File

@@ -0,0 +1,70 @@
{
"metadata": [
{
"src": [
{
"files": [
"UniTask/Assets/Plugins/UniTask/Runtime/**/*.cs"
],
"src": "../src"
}
],
"dest": "api",
"disableGitFeatures": false,
"disableDefaultFilter": false
}
],
"build": {
"globalMetadata": {
"_disableContribution": true,
"_appTitle": "UniTask"
},
"content": [
{
"files": [
"api/**.yml",
"api/index.md"
]
},
{
"files": [
"articles/**.md",
"articles/**/toc.yml",
"toc.yml",
"*.md"
]
}
],
"resource": [
{
"files": [
"images/**"
]
}
],
"overwrite": [
{
"files": [
"apidoc/**.md"
],
"exclude": [
"obj/**",
"_site/**"
]
}
],
"dest": "_site",
"globalMetadataFiles": [],
"fileMetadataFiles": [],
"template": [
"_DocfxTemplate/templates/default-v2.5.2",
"_DocfxTemplate/templates/cysharp"
],
"postProcessors": [],
"markdownEngineName": "markdig",
"noLangKeyword": false,
"keepFileLink": false,
"cleanupCacheHistory": false
}
}

8
docs/index.md Normal file
View File

@@ -0,0 +1,8 @@
---
title: Home
---
# UniTask
Provides an efficient async/await integration to Unity.
https://github.com/Cysharp/UniTask

11
docs/toc.yml Normal file
View File

@@ -0,0 +1,11 @@
- name: API Documentation
href: api/
homepage: api/Cysharp.Threading.Tasks.html
- name: Repository
href: https://github.com/Cysharp/UniTask
homepage: https://github.com/Cysharp/UniTask
- name: Releases
href: https://github.com/Cysharp/UniTask/releases
homepage: https://github.com/Cysharp/UniTask/releases

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,101 @@
#if !NETSTANDARD2_0
#pragma warning disable 0649
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace Cysharp.Threading.Tasks
{
public static class AsyncEnumerableExtensions
{
public static IUniTaskAsyncEnumerable<T> AsUniTaskAsyncEnumerable<T>(this IAsyncEnumerable<T> source)
{
return new AsyncEnumerableToUniTaskAsyncEnumerable<T>(source);
}
public static IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IUniTaskAsyncEnumerable<T> source)
{
return new UniTaskAsyncEnumerableToAsyncEnumerable<T>(source);
}
sealed class AsyncEnumerableToUniTaskAsyncEnumerable<T> : IUniTaskAsyncEnumerable<T>
{
readonly IAsyncEnumerable<T> source;
public AsyncEnumerableToUniTaskAsyncEnumerable(IAsyncEnumerable<T> source)
{
this.source = source;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
}
sealed class Enumerator : IUniTaskAsyncEnumerator<T>
{
readonly IAsyncEnumerator<T> enumerator;
public Enumerator(IAsyncEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public T Current => enumerator.Current;
public async UniTask DisposeAsync()
{
await enumerator.DisposeAsync();
}
public async UniTask<bool> MoveNextAsync()
{
return await enumerator.MoveNextAsync();
}
}
}
sealed class UniTaskAsyncEnumerableToAsyncEnumerable<T> : IAsyncEnumerable<T>
{
readonly IUniTaskAsyncEnumerable<T> source;
public UniTaskAsyncEnumerableToAsyncEnumerable(IUniTaskAsyncEnumerable<T> source)
{
this.source = source;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
}
sealed class Enumerator : IAsyncEnumerator<T>
{
readonly IUniTaskAsyncEnumerator<T> enumerator;
public Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public T Current => enumerator.Current;
public ValueTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
public ValueTask<bool> MoveNextAsync()
{
return enumerator.MoveNextAsync();
}
}
}
}
}
#endif

View File

@@ -1,6 +1,8 @@
#pragma warning disable 0649 #pragma warning disable 0649
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
{ {
@@ -8,23 +10,88 @@ namespace Cysharp.Threading.Tasks
{ {
public static ValueTask AsValueTask(this in UniTask task) public static ValueTask AsValueTask(this in UniTask task)
{ {
#if NETSTANDARD2_0
return new ValueTask(new UniTaskValueTaskSource(task), 0);
#else
return task; return task;
#endif
} }
public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task) public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
{ {
#if NETSTANDARD2_0
return new ValueTask<T>(new UniTaskValueTaskSource<T>(task), 0);
#else
return task; return task;
#endif
} }
public static UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true) public static async UniTask<T> AsUniTask<T>(this ValueTask<T> task)
{ {
// NOTE: get _obj and _token directly for low overhead conversion but not yet implemented. return await task;
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
} }
public static UniTask AsUniTask(this ValueTask task, bool useCurrentSynchronizationContext = true) public static async UniTask AsUniTask(this ValueTask task)
{ {
return task.AsTask().AsUniTask(useCurrentSynchronizationContext); await task;
} }
#if NETSTANDARD2_0
class UniTaskValueTaskSource : IValueTaskSource
{
readonly UniTask task;
readonly UniTask.Awaiter awaiter;
public UniTaskValueTaskSource(UniTask task)
{
this.task = task;
this.awaiter = task.GetAwaiter();
}
public void GetResult(short token)
{
awaiter.GetResult();
}
public ValueTaskSourceStatus GetStatus(short token)
{
return (ValueTaskSourceStatus)task.Status;
}
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
awaiter.SourceOnCompleted(continuation, state);
}
}
class UniTaskValueTaskSource<T> : IValueTaskSource<T>
{
readonly UniTask<T> task;
readonly UniTask<T>.Awaiter awaiter;
public UniTaskValueTaskSource(UniTask<T> task)
{
this.task = task;
this.awaiter = task.GetAwaiter();
}
public T GetResult(short token)
{
return awaiter.GetResult();
}
public ValueTaskSourceStatus GetStatus(short token)
{
return (ValueTaskSourceStatus)task.Status;
}
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
awaiter.SourceOnCompleted(continuation, state);
}
}
#endif
} }
} }

View File

@@ -0,0 +1,39 @@
//using Cysharp.Threading.Tasks.Internal;
//using System;
//using System.Collections.Concurrent;
//using System.Runtime.CompilerServices;
//using System.Threading;
//namespace Cysharp.Threading.Tasks
//{
// public partial struct UniTask
// {
// public static UniTask Delay()
// {
// return default;
// }
// sealed class DelayPromise : IUniTaskSource
// {
// public void GetResult(short token)
// {
// throw new NotImplementedException();
// }
// public UniTaskStatus GetStatus(short token)
// {
// throw new NotImplementedException();
// }
// public void OnCompleted(Action<object> continuation, object state, short token)
// {
// throw new NotImplementedException();
// }
// public UniTaskStatus UnsafeGetStatus()
// {
// throw new NotImplementedException();
// }
// }
// }
//}

View File

@@ -62,11 +62,12 @@ 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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(ThreadPoolWorkItem), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(ThreadPoolWorkItem), () => pool.Size);
} }
Action continuation; Action continuation;

View File

@@ -1,12 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netstandard2.1</TargetFrameworks> <TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0</TargetFrameworks>
<AssemblyName>UniTask</AssemblyName> <AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace> <RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
<!-- NuGet Packaging -->
<Id>UniTask</Id>
<PackageVersion>$(Version)</PackageVersion>
<Company>Cysharp</Company>
<Authors>Cysharp</Authors>
<Copyright>© Cysharp, Inc.</Copyright>
<PackageTags>task;async</PackageTags>
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Include="Icon.png" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" <Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs"
Exclude=" Exclude="
@@ -18,7 +36,9 @@
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
@@ -26,9 +46,7 @@
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs; ..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
" /> " />
</ItemGroup> </ItemGroup>

View File

@@ -1,4 +1,6 @@
using Cysharp.Threading.Tasks; #pragma warning disable CS1998
using Cysharp.Threading.Tasks;
using System.Linq; using System.Linq;
using System; using System;
@@ -15,6 +17,19 @@ using System.Reactive.Concurrency;
namespace NetCoreSandbox namespace NetCoreSandbox
{ {
public class MySyncContext : SynchronizationContext
{
public MySyncContext()
{
}
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Called SyncContext Post!");
base.Post(d, state);
}
}
public class Text public class Text
{ {
@@ -43,6 +58,24 @@ namespace NetCoreSandbox
} }
class Foo
{
public async UniTask MethodFooAsync()
{
await MethodBarAsync();
}
private async UniTask MethodBarAsync()
{
Throw();
}
private void Throw()
{
throw new Exception();
}
}
public struct TestAwaiter : ICriticalNotifyCompletion public struct TestAwaiter : ICriticalNotifyCompletion
{ {
@@ -193,12 +226,68 @@ namespace NetCoreSandbox
await Task.Delay(10, cancellationToken); await Task.Delay(10, cancellationToken);
} }
public class MyDisposable : IDisposable
{
public void Dispose()
{
}
}
static void Test()
{
var disp = new MyDisposable();
using var _ = new MyDisposable();
Console.WriteLine("tako");
}
static async UniTask FooBarAsync()
{
await using (UniTask.ReturnToCurrentSynchronizationContext())
{
await UniTask.SwitchToThreadPool();
}
}
static async UniTask Aaa()
{
await FooBarAsync();
Console.WriteLine("FooBarAsync End");
}
static async UniTask WhereSelect()
{
await foreach (var item in UniTaskAsyncEnumerable.Range(1, 10)
.SelectAwait(async x =>
{
await UniTask.Yield();
return x;
})
.Where(x => x % 2 == 0))
{
Console.WriteLine(item);
}
}
static async Task Main(string[] args) static async Task Main(string[] args)
{ {
#if !DEBUG #if !DEBUG
//await new AllocationCheck().ViaUniTaskVoid(); //await new AllocationCheck().ViaUniTaskVoid();
//Console.ReadLine(); //Console.ReadLine();
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
@@ -206,42 +295,25 @@ namespace NetCoreSandbox
//await new ComparisonBenchmarks().ViaUniTaskT(); //await new ComparisonBenchmarks().ViaUniTaskT();
return; return;
#endif #endif
// await new AllocationCheck().ViaUniTaskVoid();
// AsyncTest().Forget(); var e = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
//AsyncTest().Forget();
// AsyncTest().Forget();
ThreadPool.SetMinThreads(100, 100);
//List<UniTask<int>> list = new List<UniTask<int>>();
for (int i = 0; i < short.MaxValue; i++)
{ {
//// list.Add(AsyncTest()); for (int i = 0; i < 5; i++)
await YieldCore(); {
} Console.WriteLine($"Start {i}");
//await UniTask.WhenAll(list); await writer.YieldAsync(i);
Console.WriteLine($"End {i}");
}
});
//Console.WriteLine("TOGO"); var ee = e.GetAsyncEnumerator();
while (await ee.MoveNextAsync())
//var a = await AsyncTest();
//var b = AsyncTest();
//var c = AsyncTest();
await YieldCore();
//await b;
//await c;
foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPoolMonitor.GetCacheSizeInfo())
{ {
Console.WriteLine(item); Console.WriteLine("ForEach " + ee.Current);
} }
Console.ReadLine();
} }
static async UniTask YieldCore() static async UniTask YieldCore()

View File

@@ -0,0 +1,473 @@
using BenchmarkDotNet.Attributes;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
[Config(typeof(BenchmarkConfig))]
public class QueueCheck
{
Node node1 = new Node();
Node node2 = new Node();
RefNode refNode1 = new RefNode();
RefNode refNode2 = new RefNode();
Queue<Node> q1 = new Queue<Node>();
Stack<Node> s1 = new Stack<Node>();
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
static TaskPool<Node> pool;
static TaskPoolRefNode<RefNode> poolRefNode;
static TaskPoolEqualNull<Node> poolEqualNull;
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
static TaskPoolWithoutSize<Node> poolWithoutSize;
static TaskPoolWithoutLock<Node> poolWithoutLock;
[Benchmark]
public void Queue()
{
q1.Enqueue(node1);
q1.Enqueue(node1);
q1.TryDequeue(out _);
q1.TryDequeue(out _);
}
[Benchmark]
public void QueueLock()
{
lock (q1) { q1.Enqueue(node1); }
lock (q1) { q1.Enqueue(node1); }
lock (q1) { q1.TryDequeue(out _); }
lock (q1) { q1.TryDequeue(out _); }
}
[Benchmark]
public void Stack()
{
s1.Push(node1);
s1.Push(node2);
s1.TryPop(out _);
s1.TryPop(out _);
}
[Benchmark]
public void StackLock()
{
lock (s1) { s1.Push(node1); }
lock (s1) { s1.Push(node2); }
lock (s1) { s1.TryPop(out _); }
lock (s1) { s1.TryPop(out _); }
}
[Benchmark]
public void ConcurrentQueue()
{
cq.Enqueue(node1);
cq.Enqueue(node1);
cq.TryDequeue(out _);
cq.TryDequeue(out _);
}
[Benchmark]
public void ConcurrentStack()
{
cs.Push(node1);
cs.Push(node2);
cs.TryPop(out _);
cs.TryPop(out _);
}
[Benchmark]
public void TaskPool()
{
pool.TryPush(node1);
pool.TryPush(node2);
pool.TryPop(out _);
pool.TryPop(out _);
}
[Benchmark]
public void TaskPoolRefNode()
{
poolRefNode.TryPush(refNode1);
poolRefNode.TryPush(refNode2);
poolRefNode.TryPop(out _);
poolRefNode.TryPop(out _);
}
[Benchmark]
public void TaskPoolEqualNull()
{
poolEqualNull.TryPush(node1);
poolEqualNull.TryPush(node2);
poolEqualNull.TryPop(out _);
poolEqualNull.TryPop(out _);
}
[Benchmark]
public void TaskPoolClass()
{
poolClass.TryPush(node1);
poolClass.TryPush(node2);
poolClass.TryPop(out _);
poolClass.TryPop(out _);
}
[Benchmark]
public void TaskPoolWithoutSize()
{
poolWithoutSize.TryPush(node1);
poolWithoutSize.TryPush(node2);
poolWithoutSize.TryPop(out _);
poolWithoutSize.TryPop(out _);
}
[Benchmark]
public void TaskPoolWithoutLock()
{
poolWithoutLock.TryPush(node1);
poolWithoutLock.TryPush(node2);
poolWithoutLock.TryPop(out _);
poolWithoutLock.TryPop(out _);
}
}
public sealed class Node : ITaskPoolNode<Node>
{
public Node NextNode { get; set; }
}
public interface ITaskPoolNode<T>
{
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.
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolWithoutLock<T>
where T : class, ITaskPoolNode<T>
{
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
// Volatile.Write(ref gate, 0);
return true;
}
//Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
// Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
//return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPool<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
[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)]
public struct TaskPoolEqualNull<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (v != null)
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
public class TaskPoolClass<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolWithoutSize<T>
where T : class, ITaskPoolNode<T>
{
int gate;
T root;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
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;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}

View File

@@ -0,0 +1,167 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using Cysharp.Threading.Tasks.Linq;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class AsyncLazyTest
{
[Fact]
public async Task LazyLazy()
{
{
var l = UniTask.Lazy(() => After());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await a;
await b;
await c;
}
{
var l = UniTask.Lazy(() => AfterException());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
[Fact]
public async Task LazyImmediate()
{
{
var l = UniTask.Lazy(() => UniTask.FromResult(1).AsUniTask());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await a;
await b;
await c;
}
{
var l = UniTask.Lazy(() => UniTask.FromException(new TaskTestException()));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
static async UniTask AwaitAwait(UniTask t)
{
await t;
}
async UniTask After()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
await UniTask.Yield();
}
async UniTask AfterException()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
throw new TaskTestException();
}
}
public class AsyncLazyTest2
{
[Fact]
public async Task LazyLazy()
{
{
var l = UniTask.Lazy(() => After());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
var a2 = await a;
var b2 = await b;
var c2 = await c;
(a2, b2, c2).Should().Be((10, 10, 10));
}
{
var l = UniTask.Lazy(() => AfterException());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
[Fact]
public async Task LazyImmediate()
{
{
var l = UniTask.Lazy(() => UniTask.FromResult(1));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
var a2 = await a;
var b2 = await b;
var c2 = await c;
(a2, b2, c2).Should().Be((1, 1, 1));
}
{
var l = UniTask.Lazy(() => UniTask.FromException<int>(new TaskTestException()));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
static async UniTask<int> AwaitAwait(UniTask<int> t)
{
return await t;
}
async UniTask<int> After()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
await UniTask.Yield();
return 10;
}
async UniTask<int> AfterException()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
throw new TaskTestException();
}
}
}

View File

@@ -112,6 +112,85 @@ namespace NetCoreTests
state.Value.Should().Be(20); state.Value.Should().Be(20);
} }
[Fact]
public async Task WaitAsyncTest()
{
var rp = new AsyncReactiveProperty<int>(128);
var f = await rp.FirstAsync();
f.Should().Be(128);
{
var t = rp.WaitAsync();
rp.Value = 99;
rp.Value = 100;
var v = await t;
v.Should().Be(99);
}
{
var t = rp.WaitAsync();
rp.Value = 99;
rp.Value = 100;
var v = await t;
v.Should().Be(99);
}
}
[Fact]
public async Task WaitAsyncCancellationTest()
{
var cts = new CancellationTokenSource();
var rp = new AsyncReactiveProperty<int>(128);
var t = rp.WaitAsync(cts.Token);
cts.Cancel();
rp.Value = 99;
rp.Value = 100;
await Assert.ThrowsAsync<OperationCanceledException>(async () => { await t; });
}
[Fact]
public async Task ReadOnlyWaitAsyncTest()
{
var rp = new AsyncReactiveProperty<int>(128);
var rrp = rp.ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
var t = rrp.WaitAsync();
rp.Value = 99;
rp.Value = 100;
var v = await t;
v.Should().Be(99);
}
[Fact]
public async Task ReadOnlyWaitAsyncCancellationTest()
{
var cts = new CancellationTokenSource();
var rp = new AsyncReactiveProperty<int>(128);
var rrp = rp.ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
var t = rrp.WaitAsync(cts.Token);
cts.Cancel();
rp.Value = 99;
rp.Value = 100;
await Assert.ThrowsAsync<OperationCanceledException>(async () => { await t; });
}
} }

View File

@@ -0,0 +1,590 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using Cysharp.Threading.Tasks.Linq;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class CompletionSourceTest
{
[Fact]
public async Task SetFirst()
{
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetResult();
await tcs.Task; // ok.
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task SingleOnFirst()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetResult();
await a;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiOne()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetResult();
await a;
await b;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiTwo()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetResult();
await a;
await b;
await c;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await c);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
class TestException : Exception
{
}
}
public class CompletionSourceTest2
{
[Fact]
public async Task SetFirst()
{
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetResult(10);
var a = await tcs.Task; // ok.
var b = await tcs.Task; // ok.
a.Should().Be(10);
b.Should().Be(10);
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task SingleOnFirst()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await tcs.Task; // ok.
r1.Should().Be(10);
r2.Should().Be(10);
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiOne()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await b;
var r3 = await tcs.Task; // ok.
(r1, r2, r3).Should().Be((10, 10, 10));
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiTwo()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await b;
var r3 = await c;
var r4 = await tcs.Task; // ok.
(r1, r2, r3, r4).Should().Be((10, 10, 10, 10));
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await c);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
class TestException : Exception
{
}
}
}

View File

@@ -0,0 +1,170 @@
#pragma warning disable CS1998
#pragma warning disable CS0162
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests.Linq
{
public class CreateTest
{
[Fact]
public async Task SyncCreation()
{
var from = 10;
var count = 100;
var xs = await UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
for (int i = 0; i < count; i++)
{
await writer.YieldAsync(from + i);
}
}).ToArrayAsync();
var ys = await Range(from, count).AsUniTaskAsyncEnumerable().ToArrayAsync();
xs.Should().BeEquivalentTo(ys);
}
[Fact]
public async Task SyncManually()
{
var list = new List<int>();
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
list.Add(100);
await writer.YieldAsync(10);
list.Add(200);
await writer.YieldAsync(20);
list.Add(300);
await writer.YieldAsync(30);
list.Add(400);
});
list.Should().BeEmpty();
var e = xs.GetAsyncEnumerator();
list.Should().BeEmpty();
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100);
e.Current.Should().Be(10);
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100, 200);
e.Current.Should().Be(20);
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100, 200, 300);
e.Current.Should().Be(30);
(await e.MoveNextAsync()).Should().BeFalse();
list.Should().BeEquivalentTo(100, 200, 300, 400);
}
[Fact]
public async Task SyncExceptionFirst()
{
var from = 10;
var count = 100;
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
for (int i = 0; i < count; i++)
{
throw new UniTaskTestException();
await writer.YieldAsync(from + i);
}
});
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
}
[Fact]
public async Task SyncException()
{
var from = 10;
var count = 100;
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
for (int i = 0; i < count; i++)
{
await writer.YieldAsync(from + i);
if (i == 15)
{
throw new UniTaskTestException();
}
}
});
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
}
[Fact]
public async Task ASyncManually()
{
var list = new List<int>();
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
await UniTask.Yield();
list.Add(100);
await writer.YieldAsync(10);
await UniTask.Yield();
list.Add(200);
await writer.YieldAsync(20);
await UniTask.Yield();
list.Add(300);
await UniTask.Yield();
await writer.YieldAsync(30);
await UniTask.Yield();
list.Add(400);
});
list.Should().BeEmpty();
var e = xs.GetAsyncEnumerator();
list.Should().BeEmpty();
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100);
e.Current.Should().Be(10);
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100, 200);
e.Current.Should().Be(20);
await e.MoveNextAsync();
list.Should().BeEquivalentTo(100, 200, 300);
e.Current.Should().Be(30);
(await e.MoveNextAsync()).Should().BeFalse();
list.Should().BeEquivalentTo(100, 200, 300, 400);
}
async IAsyncEnumerable<int> Range(int from, int count)
{
for (int i = 0; i < count; i++)
{
yield return from + i;
}
}
}
}

View File

@@ -43,7 +43,7 @@ namespace NetCoreTests.Linq
} }
[Fact] [Fact]
public async Task TakeUntil() public async Task TakeUntilCanceled()
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@@ -72,7 +72,7 @@ namespace NetCoreTests.Linq
} }
[Fact] [Fact]
public async Task SkipUntil() public async Task SkipUntilCanceled()
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
await c; await c;
var foo = await xs; var foo = await xs;
foo.Should().BeEquivalentTo(new[] { 30, 40 }); foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
async Task CancelAsync() async Task CancelAsync()
{ {
@@ -102,5 +102,64 @@ namespace NetCoreTests.Linq
} }
} }
[Fact]
public async Task TakeUntil()
{
var cts = new AsyncReactiveProperty<int>(0);
var rp = new AsyncReactiveProperty<int>(1);
var xs = rp.TakeUntil(cts.WaitAsync()).ToArrayAsync();
var c = CancelAsync();
await c;
var foo = await xs;
foo.Should().BeEquivalentTo(new[] { 1, 10, 20 });
async Task CancelAsync()
{
rp.Value = 10;
await Task.Yield();
rp.Value = 20;
await Task.Yield();
cts.Value = 9999;
rp.Value = 30;
await Task.Yield();
rp.Value = 40;
}
}
[Fact]
public async Task SkipUntil()
{
var cts = new AsyncReactiveProperty<int>(0);
var rp = new AsyncReactiveProperty<int>(1);
var xs = rp.SkipUntil(cts.WaitAsync()).ToArrayAsync();
var c = CancelAsync();
await c;
var foo = await xs;
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
async Task CancelAsync()
{
rp.Value = 10;
await Task.Yield();
rp.Value = 20;
await Task.Yield();
cts.Value = 9999;
rp.Value = 30;
await Task.Yield();
rp.Value = 40;
rp.Dispose(); // complete.
}
}
} }
} }

View File

@@ -0,0 +1,637 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using Cysharp.Threading.Tasks.Linq;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class TriggerEventTest
{
[Fact]
public void SimpleAdd()
{
var ev = new TriggerEvent<int>();
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
{
var one = new TestEvent(1);
ev.Add(one);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.SetCompleted();
one.CompletedCalled.Count.Should().Be(1);
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
one.CompletedCalled.Count.Should().Be(1);
}
// after removed, onemore
{
var one = new TestEvent(1);
ev.Add(one);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.SetCompleted();
one.CompletedCalled.Count.Should().Be(1);
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
one.CompletedCalled.Count.Should().Be(1);
}
}
[Fact]
public void AddFour()
{
var ev = new TriggerEvent<int>();
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
{
var one = new TestEvent(1);
var two = new TestEvent(2);
var three = new TestEvent(3);
var four = new TestEvent(4);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.Add(four);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.SetCompleted();
one.CompletedCalled.Count.Should().Be(1);
two.CompletedCalled.Count.Should().Be(1);
three.CompletedCalled.Count.Should().Be(1);
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
one.CompletedCalled.Count.Should().Be(1);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.CompletedCalled.Count.Should().Be(1);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.CompletedCalled.Count.Should().Be(1);
}
// after removed, onemore.
{
var one = new TestEvent(1);
var two = new TestEvent(2);
var three = new TestEvent(3);
var four = new TestEvent(4);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.Add(four);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
ev.Add(four);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.SetCompleted();
one.CompletedCalled.Count.Should().Be(1);
two.CompletedCalled.Count.Should().Be(1);
three.CompletedCalled.Count.Should().Be(1);
// do nothing
ev.SetResult(0);
ev.SetError(null);
ev.SetCompleted();
ev.SetCanceled(default);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
one.CompletedCalled.Count.Should().Be(1);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.CompletedCalled.Count.Should().Be(1);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.CompletedCalled.Count.Should().Be(1);
}
}
[Fact]
public void OneRemove()
{
var ev = new TriggerEvent<int>();
{
var one = new TestEvent(1);
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.Remove(one);
ev.SetResult(40);
ev.SetResult(50);
ev.SetResult(60);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
}
}
[Fact]
public void TwoRemove()
{
var ev = new TriggerEvent<int>();
{
var one = new TestEvent(1);
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.Remove(two);
ev.SetResult(40);
ev.SetResult(50);
ev.SetResult(60);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
}
}
[Fact]
public void ThreeRemove()
{
var ev = new TriggerEvent<int>();
{
var one = new TestEvent(1);
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
ev.Remove(three);
ev.SetResult(40);
ev.SetResult(50);
ev.SetResult(60);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
}
[Fact]
public void RemoveSelf()
{
new RemoveMe().Run1();
new RemoveMe().Run2();
new RemoveMe().Run3();
}
[Fact]
public void RemoveNextInIterating()
{
new RemoveNext().Run1();
new RemoveNext().Run2();
new RemoveNext().Run3();
}
[Fact]
public void RemoveNextNextTest()
{
new RemoveNextNext().Run1();
new RemoveNextNext().Run2();
}
[Fact]
public void AddTest()
{
new AddMe().Run1();
new AddMe().Run2();
}
public class RemoveMe
{
TriggerEvent<int> ev;
public void Run1()
{
TestEvent one = default;
one = new TestEvent(1, () => ev.Remove(one));
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
public void Run2()
{
TestEvent one = default;
one = new TestEvent(1, () => ev.Remove(one));
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(two);
ev.Add(one); // add second.
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
public void Run3()
{
TestEvent one = default;
one = new TestEvent(1, () => ev.Remove(one));
var two = new TestEvent(2);
var three = new TestEvent(3);
ev.Add(two);
ev.Add(three);
ev.Add(one); // add thired.
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10);
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
}
public class RemoveNext
{
TriggerEvent<int> ev;
public void Run1()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
one = new TestEvent(1, () => ev.Remove(two));
two = new TestEvent(2);
three = new TestEvent(3);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Count.Should().Be(0);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
public void Run2()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
one = new TestEvent(1, () => ev.Remove(two));
two = new TestEvent(2);
three = new TestEvent(3);
ev.Add(two);
ev.Add(one); // add second
ev.Add(three);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
public void Run3()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
one = new TestEvent(1, () => ev.Remove(two));
two = new TestEvent(2);
three = new TestEvent(3);
ev.Add(two);
ev.Add(three);
ev.Add(one); // add thired.
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Should().BeEquivalentTo(10);
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
}
public class RemoveNextNext
{
TriggerEvent<int> ev;
public void Run1()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
TestEvent four = default;
one = new TestEvent(1, () => { ev.Remove(two); ev.Remove(three); });
two = new TestEvent(2);
three = new TestEvent(3);
four = new TestEvent(4);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.Add(four);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
two.NextCalled.Count.Should().Be(0);
three.NextCalled.Count.Should().Be(0);
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
public void Run2()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
TestEvent four = default;
one = new TestEvent(1, () => { ev.Remove(one); ev.Remove(two); ev.Remove(three); });
two = new TestEvent(2);
three = new TestEvent(3);
four = new TestEvent(4);
ev.Add(one);
ev.Add(two);
ev.Add(three);
ev.Add(four);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
one.NextCalled.Should().BeEquivalentTo(10);
two.NextCalled.Count.Should().Be(0);
three.NextCalled.Count.Should().Be(0);
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
}
}
public class AddMe
{
TriggerEvent<int> ev;
public void Run1()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
TestEvent four = default;
one = new TestEvent(1, () =>
{
if (two == null)
{
ev.Add(two = new TestEvent(2));
}
else if (three == null)
{
ev.Add(three = new TestEvent(3));
}
else if (four == null)
{
ev.Add(four = new TestEvent(4));
}
});
ev.Add(one);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
ev.SetResult(40);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
three.NextCalled.Should().BeEquivalentTo(30, 40);
four.NextCalled.Should().BeEquivalentTo(40);
}
public void Run2()
{
TestEvent one = default;
TestEvent two = default;
TestEvent three = default;
TestEvent four = default;
one = new TestEvent(1, () =>
{
if (two == null)
{
ev.Add(two = new TestEvent(2, () =>
{
if (three == null)
{
ev.Add(three = new TestEvent(3, () =>
{
if (four == null)
{
ev.Add(four = new TestEvent(4));
}
}));
}
}));
}
});
ev.Add(one);
ev.SetResult(10);
ev.SetResult(20);
ev.SetResult(30);
ev.SetResult(40);
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
three.NextCalled.Should().BeEquivalentTo(30, 40);
four.NextCalled.Should().BeEquivalentTo(40);
}
}
}
public class TestEvent : ITriggerHandler<int>
{
public readonly int Id;
readonly Action iteratingEvent;
public TestEvent(int id)
{
this.Id = id;
}
public TestEvent(int id, Action iteratingEvent)
{
this.Id = id;
this.iteratingEvent = iteratingEvent;
}
public List<int> NextCalled = new List<int>();
public List<Exception> ErrorCalled = new List<Exception>();
public List<object> CompletedCalled = new List<object>();
public List<CancellationToken> CancelCalled = new List<CancellationToken>();
public ITriggerHandler<int> Prev { get; set; }
public ITriggerHandler<int> Next { get; set; }
public void OnCanceled(CancellationToken cancellationToken)
{
CancelCalled.Add(cancellationToken);
}
public void OnCompleted()
{
CompletedCalled.Add(new object());
}
public void OnError(Exception ex)
{
ErrorCalled.Add(ex);
}
public void OnNext(int value)
{
NextCalled.Add(value);
iteratingEvent?.Invoke();
}
public override string ToString()
{
return Id.ToString();
}
}
}

View File

@@ -0,0 +1,40 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class WithCancellationTest
{
[Fact]
public async Task Standard()
{
CancellationTokenSource cts = new CancellationTokenSource();
var v = await UniTask.Run(() => 10).WithCancellation(cts.Token);
v.Should().Be(10);
}
[Fact]
public async Task Cancel()
{
CancellationTokenSource cts = new CancellationTokenSource();
var t = UniTask.Create(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(1));
return 10;
}).WithCancellation(cts.Token);
cts.Cancel();
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await t)).CancellationToken.Should().Be(cts.Token);
}
}
}

View File

@@ -0,0 +1,734 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace></RootNamespace>
<ProjectGuid>{CECB0124-DA37-D676-2B9E-00C5241684F4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AssemblyName>Assembly-CSharp-firstpass</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<BaseDirectory>.</BaseDirectory>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Temp\Bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;UNITY_2020_2_1;UNITY_2020_2;UNITY_2020;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;SCENE_TEMPLATE_MODULE;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;INCLUDE_DYNAMIC_GI;ENABLE_MONO_BDWGC;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;PLATFORM_STANDALONE;PLATFORM_STANDALONE_WIN;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;UNITY_PRO_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>0169</NoWarn>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Temp\bin\Release\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>0169</NoWarn>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<NoConfig>true</NoConfig>
<NoStdLib>true</NoStdLib>
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
<ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>
<ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>
</PropertyGroup>
<PropertyGroup>
<ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<UnityProjectGenerator>Package</UnityProjectGenerator>
<UnityProjectGeneratorVersion>2.0.5</UnityProjectGeneratorVersion>
<UnityProjectType>GamePlugins:3</UnityProjectType>
<UnityBuildTarget>StandaloneWindows64:19</UnityBuildTarget>
<UnityVersion>2020.2.1f1</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files (x86)\Microsoft Visual Studio Tools for Unity\16.0\Analyzers\Microsoft.Unity.Analyzers.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="Assets\Plugins\UniTask\Runtime\CompilerServices\AsyncUniTaskMethodBuilder.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\EnumerableAsyncExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\Error.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Channel.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\IUniTaskSource.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Progress.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\PooledDelegate.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.WhenAny.Generated.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskCompletionSource.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\AsyncAwakeTrigger.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CompilerServices\AsyncUniTaskVoidMethodBuilder.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\IUniTaskAsyncEnumerable.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\AsyncUnit.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\RuntimeHelpersAbstraction.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\TriggerEvent.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.Threading.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskVoid.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\TaskPool.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\AsyncTriggerBase.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityWebRequestException.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\WeakDictionary.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\ArrayPool.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\AsyncStartTrigger.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskExtensions.Shorthand.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskScheduler.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.WhenAll.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.Factory.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\ValueStopwatch.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.AssetBundleRequestAllAssets.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.Run.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\ArrayUtil.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\MoveNextSource.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\MonoBehaviourMessagesTriggers.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\ExceptionExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\AsyncReactiveProperty.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\AsyncLazy.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.WhenAny.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\MinimumQueue.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTask.WhenAll.Generated.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CompilerServices\StateMachineRunner.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\StatePool.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.AsyncGPUReadback.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.Jobs.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskObservableExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\UniTaskExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\AsyncTriggerExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CancellationTokenExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\ArrayPoolUtil.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\TaskTracker.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Triggers\AsyncDestroyTrigger.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs" />
<Compile Include="Assets\Plugins\UniTask\Runtime\CancellationTokenEqualityComparer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Assets\Plugins\UniTask\Runtime\UniTask.asmdef" />
<Reference Include="UnityEngine">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ARModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AccessibilityModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AndroidJNIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AudioModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ClusterInputModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ClusterRendererModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CrashReportingModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.DSPGraphModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.DirectorModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GameCenterModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GridModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.HotReloadModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.IMGUIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ImageConversionModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.LocalizationModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ParticleSystemModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PerformanceReportingModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ProfilerModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ScreenCaptureModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SharedInternalsModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SpriteMaskModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SpriteShapeModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.StreamingModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SubstanceModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TLSModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TerrainModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextCoreModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsNativeModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsNativeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UNETModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UNETModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UmbraModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityAnalyticsModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityConnectModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityCurlModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityTestProtocolModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VFXModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VideoModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VirtualTexturingModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.WindModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.CoreModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.GraphViewModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.PackageManagerUIModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.PackageManagerUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.SceneTemplateModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.UIElementsModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.UIElementsSamplesModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.UIServiceModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.UIServiceModule.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.UnityConnectModule">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>Library\PackageCache\com.unity.ext.nunit@1.0.5\net35\unity-custom\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="netstandard">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\ref\2.0.0\netstandard.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\Microsoft.Win32.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.AppContext">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.AppContext.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Concurrent">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Collections.Concurrent.dll</HintPath>
</Reference>
<Reference Include="System.Collections">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Collections.dll</HintPath>
</Reference>
<Reference Include="System.Collections.NonGeneric">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Collections.NonGeneric.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Specialized">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Collections.Specialized.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ComponentModel.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.EventBasedAsync">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ComponentModel.EventBasedAsync.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ComponentModel.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.TypeConverter">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ComponentModel.TypeConverter.dll</HintPath>
</Reference>
<Reference Include="System.Console">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Console.dll</HintPath>
</Reference>
<Reference Include="System.Data.Common">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Data.Common.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Contracts">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.Contracts.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Debug">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.Debug.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.FileVersionInfo">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.FileVersionInfo.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Process">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.Process.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.StackTrace">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.StackTrace.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.TextWriterTraceListener">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.TextWriterTraceListener.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tools">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.Tools.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.TraceSource">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.TraceSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tracing">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Diagnostics.Tracing.dll</HintPath>
</Reference>
<Reference Include="System.Drawing.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Drawing.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Dynamic.Runtime">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Dynamic.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Globalization.Calendars">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Globalization.Calendars.dll</HintPath>
</Reference>
<Reference Include="System.Globalization">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Globalization.dll</HintPath>
</Reference>
<Reference Include="System.Globalization.Extensions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Globalization.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.Compression.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression.ZipFile">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.Compression.ZipFile.dll</HintPath>
</Reference>
<Reference Include="System.IO">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.FileSystem.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.DriveInfo">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.FileSystem.DriveInfo.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.FileSystem.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.Watcher">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.FileSystem.Watcher.dll</HintPath>
</Reference>
<Reference Include="System.IO.IsolatedStorage">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.IsolatedStorage.dll</HintPath>
</Reference>
<Reference Include="System.IO.MemoryMappedFiles">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.MemoryMappedFiles.dll</HintPath>
</Reference>
<Reference Include="System.IO.Pipes">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.Pipes.dll</HintPath>
</Reference>
<Reference Include="System.IO.UnmanagedMemoryStream">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.IO.UnmanagedMemoryStream.dll</HintPath>
</Reference>
<Reference Include="System.Linq">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Expressions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Linq.Expressions.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Parallel">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Linq.Parallel.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Queryable">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Linq.Queryable.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.NameResolution">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.NameResolution.dll</HintPath>
</Reference>
<Reference Include="System.Net.NetworkInformation">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.NetworkInformation.dll</HintPath>
</Reference>
<Reference Include="System.Net.Ping">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Ping.dll</HintPath>
</Reference>
<Reference Include="System.Net.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Requests">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Requests.dll</HintPath>
</Reference>
<Reference Include="System.Net.Security">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Security.dll</HintPath>
</Reference>
<Reference Include="System.Net.Sockets">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.Sockets.dll</HintPath>
</Reference>
<Reference Include="System.Net.WebHeaderCollection">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.WebHeaderCollection.dll</HintPath>
</Reference>
<Reference Include="System.Net.WebSockets.Client">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.WebSockets.Client.dll</HintPath>
</Reference>
<Reference Include="System.Net.WebSockets">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Net.WebSockets.dll</HintPath>
</Reference>
<Reference Include="System.ObjectModel">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ObjectModel.dll</HintPath>
</Reference>
<Reference Include="System.Reflection">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Reflection.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.Extensions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Reflection.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Reflection.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Resources.Reader">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Resources.Reader.dll</HintPath>
</Reference>
<Reference Include="System.Resources.ResourceManager">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Resources.ResourceManager.dll</HintPath>
</Reference>
<Reference Include="System.Resources.Writer">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Resources.Writer.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.VisualC">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.CompilerServices.VisualC.dll</HintPath>
</Reference>
<Reference Include="System.Runtime">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Extensions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Handles">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Handles.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.InteropServices.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Numerics">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Numerics.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization.Formatters">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Serialization.Formatters.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization.Json">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Serialization.Json.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Serialization.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization.Xml">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Runtime.Serialization.Xml.dll</HintPath>
</Reference>
<Reference Include="System.Security.Claims">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Claims.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Cryptography.Algorithms.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Csp">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Cryptography.Csp.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Cryptography.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Cryptography.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Cryptography.X509Certificates.dll</HintPath>
</Reference>
<Reference Include="System.Security.Principal">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.Principal.dll</HintPath>
</Reference>
<Reference Include="System.Security.SecureString">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Security.SecureString.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encoding">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Text.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encoding.Extensions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Text.Encoding.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Text.RegularExpressions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Text.RegularExpressions.dll</HintPath>
</Reference>
<Reference Include="System.Threading">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Overlapped">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.Overlapped.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Parallel">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.Tasks.Parallel.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Thread">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.Thread.dll</HintPath>
</Reference>
<Reference Include="System.Threading.ThreadPool">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.ThreadPool.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Timer">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Threading.Timer.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml.ReaderWriter">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.ReaderWriter.dll</HintPath>
</Reference>
<Reference Include="System.Xml.XDocument">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.XDocument.dll</HintPath>
</Reference>
<Reference Include="System.Xml.XmlDocument">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.XmlDocument.dll</HintPath>
</Reference>
<Reference Include="System.Xml.XmlSerializer">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.XmlSerializer.dll</HintPath>
</Reference>
<Reference Include="System.Xml.XPath">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.XPath.dll</HintPath>
</Reference>
<Reference Include="System.Xml.XPath.XDocument">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netstandard\System.Xml.XPath.XDocument.dll</HintPath>
</Reference>
<Reference Include="System.Numerics.Vectors">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\Extensions\2.0.0\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.WindowsRuntime">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\Extensions\2.0.0\System.Runtime.InteropServices.WindowsRuntime.dll</HintPath>
</Reference>
<Reference Include="mscorlib">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\mscorlib.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.ComponentModel.Composition.dll</HintPath>
</Reference>
<Reference Include="System.Core">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Core.dll</HintPath>
</Reference>
<Reference Include="System.Data">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Data.dll</HintPath>
</Reference>
<Reference Include="System">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.dll</HintPath>
</Reference>
<Reference Include="System.Drawing">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Drawing.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression.FileSystem">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.IO.Compression.FileSystem.dll</HintPath>
</Reference>
<Reference Include="System.Net">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Net.dll</HintPath>
</Reference>
<Reference Include="System.Numerics">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Numerics.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Runtime.Serialization.dll</HintPath>
</Reference>
<Reference Include="System.ServiceModel.Web">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.ServiceModel.Web.dll</HintPath>
</Reference>
<Reference Include="System.Transactions">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Transactions.dll</HintPath>
</Reference>
<Reference Include="System.Web">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Web.dll</HintPath>
</Reference>
<Reference Include="System.Windows">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Windows.dll</HintPath>
</Reference>
<Reference Include="System.Xml">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Xml.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Xml.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Serialization">
<HintPath>C:\Program Files\Unity\Hub\Editor\2020.2.1f1\Editor\Data\NetStandard\compat\2.0.0\shims\netfx\System.Xml.Serialization.dll</HintPath>
</Reference>
<Reference Include="Unity.VSCode.Editor">
<HintPath>Library\ScriptAssemblies\Unity.VSCode.Editor.dll</HintPath>
</Reference>
<Reference Include="UnityEditor.CacheServer">
<HintPath>Library\ScriptAssemblies\UnityEditor.CacheServer.dll</HintPath>
</Reference>
<Reference Include="Unity.VisualStudio.Editor">
<HintPath>Library\ScriptAssemblies\Unity.VisualStudio.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.Addressables">
<HintPath>Library\ScriptAssemblies\Unity.Addressables.dll</HintPath>
</Reference>
<Reference Include="Unity.ScriptableBuildPipeline">
<HintPath>Library\ScriptAssemblies\Unity.ScriptableBuildPipeline.dll</HintPath>
</Reference>
<Reference Include="Unity.Addressables.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Addressables.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.ScriptableBuildPipeline.Editor">
<HintPath>Library\ScriptAssemblies\Unity.ScriptableBuildPipeline.Editor.dll</HintPath>
</Reference>
<Reference Include="Unity.ResourceManager">
<HintPath>Library\ScriptAssemblies\Unity.ResourceManager.dll</HintPath>
</Reference>
<Reference Include="Unity.Rider.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Rider.Editor.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="UniTask.TextMeshPro.csproj">
<Project>{B5929667-6CB2-8779-D894-4F69110C1A43}</Project>
<Name>UniTask.TextMeshPro</Name>
</ProjectReference>
<ProjectReference Include="TempAsm.csproj">
<Project>{9E0EF10C-B6E1-E08E-3160-7162D66F7EE0}</Project>
<Name>TempAsm</Name>
</ProjectReference>
<ProjectReference Include="UniTask.DOTween.csproj">
<Project>{7121D833-D063-D143-CFFC-CD50DDF1B3D1}</Project>
<Name>UniTask.DOTween</Name>
</ProjectReference>
<ProjectReference Include="UniTask.Addressables.csproj">
<Project>{78124C71-0355-1FB9-3AEB-7D573CD8E7CA}</Project>
<Name>UniTask.Addressables</Name>
</ProjectReference>
<ProjectReference Include="UniTask.Linq.csproj">
<Project>{7F0F67EA-D985-C15F-AAE8-F643789B52A7}</Project>
<Name>UniTask.Linq</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="GenerateTargetFrameworkMonikerAttribute" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -20,8 +20,9 @@ public static class EditorRunnerChecker
{ {
Debug.Log("Start"); Debug.Log("Start");
var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask(); //var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
Debug.Log(r.downloadHandler.text.Substring(0, 100)); //Debug.Log(r.downloadHandler.text.Substring(0, 100));
await UniTask.Yield();
Debug.Log("End"); Debug.Log("End");
} }

View File

@@ -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

View File

@@ -7,113 +7,239 @@ namespace Cysharp.Threading.Tasks
{ {
public class AsyncLazy public class AsyncLazy
{ {
Func<UniTask> valueFactory; static Action<object> continuation = SetCompletionSource;
UniTask target;
Func<UniTask> taskFactory;
UniTaskCompletionSource completionSource;
UniTask.Awaiter awaiter;
object syncLock; object syncLock;
bool initialized; bool initialized;
public AsyncLazy(Func<UniTask> valueFactory) public AsyncLazy(Func<UniTask> taskFactory)
{ {
this.valueFactory = valueFactory; this.taskFactory = taskFactory;
this.target = default; this.completionSource = new UniTaskCompletionSource();
this.syncLock = new object(); this.syncLock = new object();
this.initialized = false; this.initialized = false;
} }
internal AsyncLazy(UniTask value) internal AsyncLazy(UniTask task)
{ {
this.valueFactory = null; this.taskFactory = null;
this.target = value; this.completionSource = new UniTaskCompletionSource();
this.syncLock = null; this.syncLock = null;
this.initialized = true; this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
} }
public UniTask Task => EnsureInitialized(); public UniTask Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
UniTask EnsureInitialized() public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{ {
if (Volatile.Read(ref initialized)) if (Volatile.Read(ref initialized))
{ {
return target; return;
} }
return EnsureInitializedCore(); EnsureInitializedCore();
} }
UniTask EnsureInitializedCore() void EnsureInitializedCore()
{ {
lock (syncLock) lock (syncLock)
{ {
if (!Volatile.Read(ref initialized)) if (!Volatile.Read(ref initialized))
{ {
var f = Interlocked.Exchange(ref valueFactory, null); var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null) if (f != null)
{ {
target = f().Preserve(); // with preserve(allow multiple await). var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true); Volatile.Write(ref initialized, true);
} }
} }
} }
}
return target; void SetCompletionSource(in UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
completionSource.TrySetResult();
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy)state;
try
{
self.awaiter.GetResult();
self.completionSource.TrySetResult();
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
} }
} }
public class AsyncLazy<T> public class AsyncLazy<T>
{ {
Func<UniTask<T>> valueFactory; static Action<object> continuation = SetCompletionSource;
UniTask<T> target;
Func<UniTask<T>> taskFactory;
UniTaskCompletionSource<T> completionSource;
UniTask<T>.Awaiter awaiter;
object syncLock; object syncLock;
bool initialized; bool initialized;
public AsyncLazy(Func<UniTask<T>> valueFactory) public AsyncLazy(Func<UniTask<T>> taskFactory)
{ {
this.valueFactory = valueFactory; this.taskFactory = taskFactory;
this.target = default; this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = new object(); this.syncLock = new object();
this.initialized = false; this.initialized = false;
} }
internal AsyncLazy(UniTask<T> value) internal AsyncLazy(UniTask<T> task)
{ {
this.valueFactory = null; this.taskFactory = null;
this.target = value; this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = null; this.syncLock = null;
this.initialized = true; this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
} }
public UniTask<T> Task => EnsureInitialized(); public UniTask<T> Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask<T>.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
UniTask<T> EnsureInitialized() public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{ {
if (Volatile.Read(ref initialized)) if (Volatile.Read(ref initialized))
{ {
return target; return;
} }
return EnsureInitializedCore(); EnsureInitializedCore();
} }
UniTask<T> EnsureInitializedCore() void EnsureInitializedCore()
{ {
lock (syncLock) lock (syncLock)
{ {
if (!Volatile.Read(ref initialized)) if (!Volatile.Read(ref initialized))
{ {
var f = Interlocked.Exchange(ref valueFactory, null); var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null) if (f != null)
{ {
target = f().Preserve(); // with preserve(allow multiple await). var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true); Volatile.Write(ref initialized, true);
} }
} }
} }
}
return target; void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
{
try
{
var result = awaiter.GetResult();
completionSource.TrySetResult(result);
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy<T>)state;
try
{
var result = self.awaiter.GetResult();
self.completionSource.TrySetResult(result);
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using Cysharp.Threading.Tasks.Linq; using System;
using System;
using System.Threading; using System.Threading;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
@@ -8,6 +7,7 @@ namespace Cysharp.Threading.Tasks
{ {
T Value { get; } T Value { get; }
IUniTaskAsyncEnumerable<T> WithoutCurrent(); IUniTaskAsyncEnumerable<T> WithoutCurrent();
UniTask<T> WaitAsync(CancellationToken cancellationToken = default);
} }
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T> public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
@@ -70,6 +70,11 @@ namespace Cysharp.Threading.Tasks
return latestValue?.ToString(); return latestValue?.ToString();
} }
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
{
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
}
static bool isValueType; static bool isValueType;
static AsyncReactiveProperty() static AsyncReactiveProperty()
@@ -77,7 +82,136 @@ namespace Cysharp.Threading.Tasks
isValueType = typeof(T).IsValueType; isValueType = typeof(T).IsValueType;
} }
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T> sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
{
static Action<object> cancellationCallback = CancellationCallback;
static TaskPool<WaitAsyncSource> pool;
WaitAsyncSource nextNode;
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
static WaitAsyncSource()
{
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
}
AsyncReactiveProperty<T> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<T> core;
WaitAsyncSource()
{
}
public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitAsyncSource();
}
result.parent = parent;
result.cancellationToken = cancellationToken;
if (cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
}
result.parent.triggerEvent.Add(result);
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
return result;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationTokenRegistration.Dispose();
cancellationTokenRegistration = default;
parent.triggerEvent.Remove(this);
parent = null;
cancellationToken = default;
return pool.TryPush(this);
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;
self.OnCanceled(self.cancellationToken);
}
// IUniTaskSource
public T GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
// ITriggerHandler
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public void OnCanceled(CancellationToken cancellationToken)
{
core.TrySetCanceled(cancellationToken);
}
public void OnCompleted()
{
// Complete as Cancel.
core.TrySetCanceled(CancellationToken.None);
}
public void OnError(Exception ex)
{
core.TrySetException(ex);
}
public void OnNext(T value)
{
core.TrySetResult(value);
}
}
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
{ {
readonly AsyncReactiveProperty<T> parent; readonly AsyncReactiveProperty<T> parent;
@@ -120,6 +254,9 @@ namespace Cysharp.Threading.Tasks
public T Current => value; public T Current => value;
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {
// raise latest value on first call. // raise latest value on first call.
@@ -251,6 +388,11 @@ namespace Cysharp.Threading.Tasks
return latestValue?.ToString(); return latestValue?.ToString();
} }
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
{
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
}
static bool isValueType; static bool isValueType;
static ReadOnlyAsyncReactiveProperty() static ReadOnlyAsyncReactiveProperty()
@@ -258,7 +400,136 @@ namespace Cysharp.Threading.Tasks
isValueType = typeof(T).IsValueType; isValueType = typeof(T).IsValueType;
} }
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T> sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
{
static Action<object> cancellationCallback = CancellationCallback;
static TaskPool<WaitAsyncSource> pool;
WaitAsyncSource nextNode;
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
static WaitAsyncSource()
{
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
}
ReadOnlyAsyncReactiveProperty<T> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<T> core;
WaitAsyncSource()
{
}
public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitAsyncSource();
}
result.parent = parent;
result.cancellationToken = cancellationToken;
if (cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
}
result.parent.triggerEvent.Add(result);
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
return result;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationTokenRegistration.Dispose();
cancellationTokenRegistration = default;
parent.triggerEvent.Remove(this);
parent = null;
cancellationToken = default;
return pool.TryPush(this);
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;
self.OnCanceled(self.cancellationToken);
}
// IUniTaskSource
public T GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
// ITriggerHandler
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public void OnCanceled(CancellationToken cancellationToken)
{
core.TrySetCanceled(cancellationToken);
}
public void OnCompleted()
{
// Complete as Cancel.
core.TrySetCanceled(CancellationToken.None);
}
public void OnError(Exception ex)
{
core.TrySetException(ex);
}
public void OnNext(T value)
{
core.TrySetResult(value);
}
}
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
{ {
readonly ReadOnlyAsyncReactiveProperty<T> parent; readonly ReadOnlyAsyncReactiveProperty<T> parent;
@@ -300,6 +571,8 @@ namespace Cysharp.Threading.Tasks
} }
public T Current => value; public T Current => value;
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {

View File

@@ -9,6 +9,56 @@ namespace Cysharp.Threading.Tasks
public static class CancellationTokenExtensions public static class CancellationTokenExtensions
{ {
static readonly Action<object> cancellationTokenCallback = Callback; static readonly Action<object> cancellationTokenCallback = Callback;
static readonly Action<object> disposeCallback = DisposeCallback;
public static CancellationToken ToCancellationToken(this UniTask task)
{
var cts = new CancellationTokenSource();
ToCancellationTokenCore(task, cts).Forget();
return cts.Token;
}
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
{
if (linkToken.IsCancellationRequested)
{
return linkToken;
}
if (!linkToken.CanBeCanceled)
{
return ToCancellationToken(task);
}
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
ToCancellationTokenCore(task, cts).Forget();
return cts.Token;
}
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
{
return ToCancellationToken(task.AsUniTask());
}
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
{
return ToCancellationToken(task.AsUniTask(), linkToken);
}
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
{
try
{
await task;
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
cts.Cancel();
cts.Dispose();
}
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken) public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
{ {
@@ -75,6 +125,17 @@ namespace Cysharp.Threading.Tasks
} }
} }
} }
public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
{
return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
}
static void DisposeCallback(object state)
{
var d = (IDisposable)state;
d.Dispose();
}
} }
public struct CancellationTokenAwaitable public struct CancellationTokenAwaitable

View File

@@ -9,15 +9,15 @@ namespace Cysharp.Threading.Tasks
{ {
public static class CancellationTokenSourceExtensions public static class CancellationTokenSourceExtensions
{ {
public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
{ {
var delay = UniTask.Delay(millisecondsDelay, ignoreTimeScale, delayTiming, cts.Token); var delay = UniTask.Delay(millisecondsDelay, delayType, delayTiming, cts.Token);
CancelAfterCore(cts, delay).Forget(); CancelAfterCore(cts, delay).Forget();
} }
public static void CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) public static void CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
{ {
var delay = UniTask.Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cts.Token); var delay = UniTask.Delay(delayTimeSpan, delayType, delayTiming, cts.Token);
CancelAfterCore(cts, delay).Forget(); CancelAfterCore(cts, delay).Forget();
} }

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder public struct AsyncUniTaskMethodBuilder
{ {
internal IMoveNextRunnerPromise runnerPromise; IStateMachineRunnerPromise runnerPromise;
Exception ex; Exception ex;
// 1. Static Create method. // 1. Static Create method.
@@ -47,6 +47,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 3. SetException // 3. SetException
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception) public void SetException(Exception exception)
{ {
if (runnerPromise == null) if (runnerPromise == null)
@@ -61,6 +62,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 4. SetResult // 4. SetResult
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult() public void SetResult()
{ {
if (runnerPromise != null) if (runnerPromise != null)
@@ -71,13 +73,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 5. AwaitOnCompleted // 5. AwaitOnCompleted
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runnerPromise == null) if (runnerPromise == null)
{ {
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine); AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
} }
awaiter.OnCompleted(runnerPromise.MoveNext); awaiter.OnCompleted(runnerPromise.MoveNext);
@@ -86,13 +89,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 6. AwaitUnsafeOnCompleted // 6. AwaitUnsafeOnCompleted
[DebuggerHidden] [DebuggerHidden]
[SecuritySafeCritical] [SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runnerPromise == null) if (runnerPromise == null)
{ {
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine); AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
} }
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext); awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
@@ -100,6 +104,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 7. Start // 7. Start
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
@@ -133,7 +138,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder<T> public struct AsyncUniTaskMethodBuilder<T>
{ {
internal IMoveNextRunnerPromise<T> runnerPromise; IStateMachineRunnerPromise<T> runnerPromise;
Exception ex; Exception ex;
T result; T result;
@@ -146,9 +151,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
// 2. TaskLike Task property. // 2. TaskLike Task property.
[DebuggerHidden]
public UniTask<T> Task public UniTask<T> Task
{ {
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get get
{ {
if (runnerPromise != null) if (runnerPromise != null)
@@ -168,6 +174,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 3. SetException // 3. SetException
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception) public void SetException(Exception exception)
{ {
if (runnerPromise == null) if (runnerPromise == null)
@@ -182,6 +189,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 4. SetResult // 4. SetResult
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult(T result) public void SetResult(T result)
{ {
if (runnerPromise == null) if (runnerPromise == null)
@@ -196,13 +204,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 5. AwaitOnCompleted // 5. AwaitOnCompleted
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runnerPromise == null) if (runnerPromise == null)
{ {
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine); AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
} }
awaiter.OnCompleted(runnerPromise.MoveNext); awaiter.OnCompleted(runnerPromise.MoveNext);
@@ -211,13 +220,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 6. AwaitUnsafeOnCompleted // 6. AwaitUnsafeOnCompleted
[DebuggerHidden] [DebuggerHidden]
[SecuritySafeCritical] [SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runnerPromise == null) if (runnerPromise == null)
{ {
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine); AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
} }
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext); awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
@@ -225,6 +235,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 7. Start // 7. Start
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskVoidMethodBuilder public struct AsyncUniTaskVoidMethodBuilder
{ {
internal IMoveNextRunner runner; IStateMachineRunner runner;
// 1. Static Create method. // 1. Static Create method.
[DebuggerHidden] [DebuggerHidden]
@@ -35,12 +35,18 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 3. SetException // 3. SetException
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception) public void SetException(Exception exception)
{ {
// runner is finished, return first. // runner is finished, return first.
if (runner != null) if (runner != null)
{ {
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
#else
runner.Return(); runner.Return();
#endif
runner = null; runner = null;
} }
@@ -49,25 +55,32 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 4. SetResult // 4. SetResult
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult() public void SetResult()
{ {
// runner is finished, return. // runner is finished, return.
if (runner != null) if (runner != null)
{ {
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
#else
runner.Return(); runner.Return();
#endif
runner = null; runner = null;
} }
} }
// 5. AwaitOnCompleted // 5. AwaitOnCompleted
[DebuggerHidden] [DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runner == null) if (runner == null)
{ {
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine); AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
} }
awaiter.OnCompleted(runner.MoveNext); awaiter.OnCompleted(runner.MoveNext);
@@ -76,13 +89,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
// 6. AwaitUnsafeOnCompleted // 6. AwaitUnsafeOnCompleted
[DebuggerHidden] [DebuggerHidden]
[SecuritySafeCritical] [SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
if (runner == null) if (runner == null)
{ {
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine); AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
} }
awaiter.UnsafeOnCompleted(runner.MoveNext); awaiter.UnsafeOnCompleted(runner.MoveNext);

View File

@@ -1,19 +1,28 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS1591
using Cysharp.Threading.Tasks.Internal; using Cysharp.Threading.Tasks.Internal;
using System; using System;
using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.CompilerServices namespace Cysharp.Threading.Tasks.CompilerServices
{ {
public interface IMoveNextRunner // #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
// but currently it is labeled `Won't Fix`.
internal interface IStateMachineRunner
{ {
Action MoveNext { get; } Action MoveNext { get; }
void Return(); void Return();
#if ENABLE_IL2CPP
Action ReturnAction { get; }
#endif
} }
internal interface IMoveNextRunnerPromise : IUniTaskSource internal interface IStateMachineRunnerPromise : IUniTaskSource
{ {
Action MoveNext { get; } Action MoveNext { get; }
UniTask Task { get; } UniTask Task { get; }
@@ -21,7 +30,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
void SetException(Exception exception); void SetException(Exception exception);
} }
internal interface IMoveNextRunnerPromise<T> : IUniTaskSource<T> internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T>
{ {
Action MoveNext { get; } Action MoveNext { get; }
UniTask<T> Task { get; } UniTask<T> Task { get; }
@@ -29,11 +38,26 @@ namespace Cysharp.Threading.Tasks.CompilerServices
void SetException(Exception exception); void SetException(Exception exception);
} }
internal sealed class AsyncUniTaskVoid<TStateMachine> : IMoveNextRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource internal static class StateMachineUtility
{
// Get AsyncStateMachine internal state to check IL2CPP bug
public static int GetState(IAsyncStateMachine stateMachine)
{
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.First(x => x.Name.EndsWith("__state"));
return (int)info.GetValue(stateMachine);
}
}
internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool; static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
#if ENABLE_IL2CPP
public Action ReturnAction { get; }
#endif
TStateMachine stateMachine; TStateMachine stateMachine;
public Action MoveNext { get; } public Action MoveNext { get; }
@@ -41,9 +65,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
public AsyncUniTaskVoid() public AsyncUniTaskVoid()
{ {
MoveNext = Run; MoveNext = Run;
#if ENABLE_IL2CPP
ReturnAction = Return;
#endif
} }
public static void SetStateMachine(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine) public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
{ {
if (!pool.TryPop(out var result)) if (!pool.TryPop(out var result))
{ {
@@ -51,16 +78,17 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
builder.runner = result; // set runner before copied. runnerFieldRef = result; // set runner before copied.
result.stateMachine = stateMachine; // copy struct StateMachine(in release build). result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
} }
static AsyncUniTaskVoid() static AsyncUniTaskVoid()
{ {
TaskPoolMonitor.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()
{ {
@@ -97,23 +125,28 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
} }
internal sealed class AsyncUniTask<TStateMachine> : IMoveNextRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>> internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
static TaskPool<AsyncUniTask<TStateMachine>> pool; static TaskPool<AsyncUniTask<TStateMachine>> pool;
TStateMachine stateMachine; #if ENABLE_IL2CPP
readonly Action returnDelegate;
#endif
public Action MoveNext { get; } public Action MoveNext { get; }
TStateMachine stateMachine;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncUniTask() AsyncUniTask()
{ {
MoveNext = Run; MoveNext = Run;
#if ENABLE_IL2CPP
returnDelegate = Return;
#endif
} }
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine) public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
{ {
if (!pool.TryPop(out var result)) if (!pool.TryPop(out var result))
{ {
@@ -121,15 +154,24 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
builder.runnerPromise = result; // set runner before copied. runnerPromiseFieldRef = result; // set runner before copied.
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
}
void Return()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
pool.TryPush(this);
} }
bool TryReturn() bool TryReturn()
@@ -177,7 +219,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
finally finally
{ {
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
#else
TryReturn(); TryReturn();
#endif
} }
} }
@@ -198,33 +245,31 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
core.OnCompleted(continuation, state, token); core.OnCompleted(continuation, state, token);
} }
~AsyncUniTask()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
internal sealed class AsyncUniTask<TStateMachine, T> : IMoveNextRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>> internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
where TStateMachine : IAsyncStateMachine where TStateMachine : IAsyncStateMachine
{ {
static TaskPool<AsyncUniTask<TStateMachine, T>> pool; static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
TStateMachine stateMachine; #if ENABLE_IL2CPP
readonly Action returnDelegate;
#endif
public Action MoveNext { get; } public Action MoveNext { get; }
TStateMachine stateMachine;
UniTaskCompletionSourceCore<T> core; UniTaskCompletionSourceCore<T> core;
AsyncUniTask() AsyncUniTask()
{ {
MoveNext = Run; MoveNext = Run;
#if ENABLE_IL2CPP
returnDelegate = Return;
#endif
} }
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine) public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
{ {
if (!pool.TryPop(out var result)) if (!pool.TryPop(out var result))
{ {
@@ -232,15 +277,24 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
builder.runnerPromise = result; // set runner before copied. runnerPromiseFieldRef = result; // set runner before copied.
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
}
void Return()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
pool.TryPush(this);
} }
bool TryReturn() bool TryReturn()
@@ -255,6 +309,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run() void Run()
{ {
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
stateMachine.MoveNext(); stateMachine.MoveNext();
} }
@@ -288,7 +343,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
} }
finally finally
{ {
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
#else
TryReturn(); TryReturn();
#endif
} }
} }
@@ -315,14 +375,6 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
core.OnCompleted(continuation, state, token); core.OnCompleted(continuation, state, token);
} }
~AsyncUniTask()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
} }

View File

@@ -12,10 +12,12 @@ namespace Cysharp.Threading.Tasks
{ {
public static class EnumeratorAsyncExtensions public static class EnumeratorAsyncExtensions
{ {
public static UniTask.Awaiter GetAwaiter(this IEnumerator enumerator) public static UniTask.Awaiter GetAwaiter<T>(this T enumerator)
where T : IEnumerator
{ {
Error.ThrowArgumentNullException(enumerator, nameof(enumerator)); var e = (IEnumerator)enumerator;
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter(); Error.ThrowArgumentNullException(e, nameof(enumerator));
return new UniTask(EnumeratorPromise.Create(e, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
} }
public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken) public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
@@ -30,18 +32,35 @@ namespace Cysharp.Threading.Tasks
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token); return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
} }
public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
{
var source = AutoResetUniTaskCompletionSource.Create();
coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, source));
return source.Task;
}
static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
{
yield return coroutineRunner.StartCoroutine(inner);
source.TrySetResult();
}
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
} }
IEnumerator innerEnumerator; IEnumerator innerEnumerator;
CancellationToken cancellationToken; CancellationToken cancellationToken;
int initialFrame;
bool loopRunning;
bool calledGetResult;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@@ -64,10 +83,18 @@ namespace Cysharp.Threading.Tasks
result.innerEnumerator = ConsumeEnumerator(innerEnumerator); result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.loopRunning = true;
PlayerLoopHelper.AddAction(timing, result); result.calledGetResult = false;
result.initialFrame = -1;
token = result.core.Version; token = result.core.Version;
// run immediately.
if (result.MoveNext())
{
PlayerLoopHelper.AddAction(timing, result);
}
return result; return result;
} }
@@ -75,11 +102,15 @@ namespace Cysharp.Threading.Tasks
{ {
try try
{ {
calledGetResult = true;
core.GetResult(token); core.GetResult(token);
} }
finally finally
{ {
TryReturn(); if (!loopRunning)
{
TryReturn();
}
} }
} }
@@ -100,12 +131,38 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext() public bool MoveNext()
{ {
if (calledGetResult)
{
loopRunning = false;
TryReturn();
return false;
}
if (innerEnumerator == null) // invalid status, returned but loop running?
{
return false;
}
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
loopRunning = false;
core.TrySetCanceled(cancellationToken); core.TrySetCanceled(cancellationToken);
return false; return false;
} }
if (initialFrame == -1)
{
// Time can not touch in threadpool.
if (PlayerLoopHelper.IsMainThread)
{
initialFrame = Time.frameCount;
}
}
else if (initialFrame == Time.frameCount)
{
return true; // already executed in first frame, skip.
}
try try
{ {
if (innerEnumerator.MoveNext()) if (innerEnumerator.MoveNext())
@@ -115,10 +172,12 @@ namespace Cysharp.Threading.Tasks
} }
catch (Exception ex) catch (Exception ex)
{ {
loopRunning = false;
core.TrySetException(ex); core.TrySetException(ex);
return false; return false;
} }
loopRunning = false;
core.TrySetResult(null); core.TrySetResult(null);
return false; return false;
} }
@@ -129,15 +188,8 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
innerEnumerator = default; innerEnumerator = default;
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this);
}
~EnumeratorPromise() return pool.TryPush(this);
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
} }
// Unwrap YieldInstructions // Unwrap YieldInstructions
@@ -151,11 +203,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;
} }
@@ -181,7 +232,7 @@ namespace Cysharp.Threading.Tasks
} }
else else
{ {
yield return null; goto WARN;
} }
} }
else if (current is IEnumerator e3) else if (current is IEnumerator e3)
@@ -194,17 +245,14 @@ namespace Cysharp.Threading.Tasks
} }
else else
{ {
// WaitForEndOfFrame, WaitForFixedUpdate, others. goto WARN;
yield return null;
} }
}
}
// WWW and others as CustomYieldInstruction. continue;
static IEnumerator UnwrapWaitCustomYieldInstruction(CustomYieldInstruction yieldInstruction)
{ WARN:
while (yieldInstruction.keepWaiting) // WaitForEndOfFrame, WaitForFixedUpdate, others.
{ UnityEngine.Debug.LogWarning($"yield {current.GetType().Name} is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead.");
yield return null; yield return null;
} }
} }
@@ -214,12 +262,12 @@ namespace Cysharp.Threading.Tasks
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;
@@ -236,5 +284,4 @@ namespace Cysharp.Threading.Tasks
} }
} }
} }
} }

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a5b9231662e24c942b544bd85d4b39cb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -11,24 +11,39 @@ using UnityEngine.ResourceManagement.AsyncOperations;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
{ {
public static class AddressableAsyncExtensions public static class AddressablesAsyncExtensions
{ {
#region AsyncOperationHandle #region AsyncOperationHandle
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle) public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
{ {
return new AsyncOperationHandleAwaiter(handle); return ToUniTask(handle).GetAwaiter();
} }
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken) public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
{ {
if (handle.IsDone) return UniTask.CompletedTask; return ToUniTask(handle, cancellationToken: cancellationToken);
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
} }
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (handle.IsDone) return UniTask.CompletedTask; if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
if (!handle.IsValid())
{
// autoReleaseHandle:true handle is invalid(immediately internal handle == null) so return completed.
return UniTask.CompletedTask;
}
if (handle.IsDone)
{
if (handle.Status == AsyncOperationStatus.Failed)
{
return UniTask.FromException(handle.OperationException);
}
return UniTask.CompletedTask;
}
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token); return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
} }
@@ -80,22 +95,25 @@ 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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
} }
readonly Action<AsyncOperationHandle> continuationAction;
AsyncOperationHandle handle; AsyncOperationHandle handle;
IProgress<float> progress;
CancellationToken cancellationToken; CancellationToken cancellationToken;
IProgress<float> progress;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationHandleConfiguredSource() AsyncOperationHandleConfiguredSource()
{ {
continuationAction = Continuation;
} }
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
@@ -113,26 +131,47 @@ namespace Cysharp.Threading.Tasks
result.handle = handle; result.handle = handle;
result.progress = progress; result.progress = progress;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
handle.Completed += result.continuationAction;
token = result.core.Version; token = result.core.Version;
return result; return result;
} }
public void GetResult(short token) void Continuation(AsyncOperationHandle _)
{ {
try handle.Completed -= continuationAction;
{
core.GetResult(token); if (completed)
}
finally
{ {
TryReturn(); TryReturn();
} }
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
}
}
public void GetResult(short token)
{
core.GetResult(token);
} }
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
@@ -152,138 +191,95 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext() public bool MoveNext()
{ {
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
completed = true;
core.TrySetCanceled(cancellationToken); core.TrySetCanceled(cancellationToken);
return false; return false;
} }
if (progress != null) if (progress != null && handle.IsValid())
{ {
progress.Report(handle.PercentComplete); progress.Report(handle.PercentComplete);
} }
if (handle.IsDone)
{
if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
return false;
}
return true; return true;
} }
bool TryReturn() bool TryReturn()
{ {
core.Reset();
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset();
handle = default; handle = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
~AsyncOperationHandleConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
#endregion #endregion
#region AsyncOperationHandle_T #region AsyncOperationHandle_T
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle) public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
{ {
return new AsyncOperationHandleAwaiter<T>(handle); return ToUniTask(handle).GetAwaiter();
} }
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken) public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
{ {
if (handle.IsDone) return UniTask.FromResult(handle.Result); return ToUniTask(handle, cancellationToken: cancellationToken);
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
} }
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (handle.IsDone) return UniTask.FromResult(handle.Result); if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
}
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion if (!handle.IsValid())
{
AsyncOperationHandle<T> handle;
Action<AsyncOperationHandle> continuationAction;
public AsyncOperationHandleAwaiter(AsyncOperationHandle<T> handle)
{ {
this.handle = handle; throw new Exception("Attempting to use an invalid operation handle");
this.continuationAction = null;
} }
public bool IsCompleted => handle.IsDone; if (handle.IsDone)
public T GetResult()
{ {
if (continuationAction != null)
{
handle.CompletedTypeless -= continuationAction;
continuationAction = null;
}
if (handle.Status == AsyncOperationStatus.Failed) if (handle.Status == AsyncOperationStatus.Failed)
{ {
var e = handle.OperationException; return UniTask.FromException<T>(handle.OperationException);
handle = default;
ExceptionDispatchInfo.Capture(e).Throw();
} }
return UniTask.FromResult(handle.Result);
var result = handle.Result;
handle = default;
return result;
} }
public void OnCompleted(Action continuation) return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
handle.CompletedTypeless += continuationAction;
}
} }
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
} }
readonly Action<AsyncOperationHandle<T>> continuationAction;
AsyncOperationHandle<T> handle; AsyncOperationHandle<T> handle;
IProgress<float> progress;
CancellationToken cancellationToken; CancellationToken cancellationToken;
IProgress<float> progress;
bool completed;
UniTaskCompletionSourceCore<T> core; UniTaskCompletionSourceCore<T> core;
AsyncOperationHandleConfiguredSource() AsyncOperationHandleConfiguredSource()
{ {
continuationAction = Continuation;
} }
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token) public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
@@ -299,27 +295,49 @@ namespace Cysharp.Threading.Tasks
} }
result.handle = handle; result.handle = handle;
result.progress = progress;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.completed = false;
result.progress = progress;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
handle.Completed += result.continuationAction;
token = result.core.Version; token = result.core.Version;
return result; return result;
} }
public T GetResult(short token) void Continuation(AsyncOperationHandle<T> argHandle)
{ {
try handle.Completed -= continuationAction;
{
return core.GetResult(token); if (completed)
}
finally
{ {
TryReturn(); TryReturn();
} }
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (argHandle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(argHandle.OperationException);
}
else
{
core.TrySetResult(argHandle.Result);
}
}
}
public T GetResult(short token)
{
return core.GetResult(token);
} }
void IUniTaskSource.GetResult(short token) void IUniTaskSource.GetResult(short token)
@@ -344,30 +362,24 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext() public bool MoveNext()
{ {
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
completed = true;
core.TrySetCanceled(cancellationToken); core.TrySetCanceled(cancellationToken);
return false; return false;
} }
if (progress != null) if (progress != null && handle.IsValid())
{ {
progress.Report(handle.PercentComplete); progress.Report(handle.PercentComplete);
} }
if (handle.IsDone)
{
if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
core.TrySetResult(handle.Result);
}
return false;
}
return true; return true;
} }
@@ -380,17 +392,9 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
~AsyncOperationHandleConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
#endregion #endregion
} }
} }

View File

@@ -0,0 +1,22 @@
{
"name": "UniTask.Addressables",
"references": [
"UniTask",
"Unity.ResourceManager"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.addressables",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 593a5b492d29ac6448b1ebf7f035ef33
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25cb2f742bfeb1d48a4e65d3140b955d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,458 @@
// asmdef Version Defines, enabled when com.demigiant.dotween is imported.
#if UNITASK_DOTWEEN_SUPPORT
using Cysharp.Threading.Tasks.Internal;
using DG.Tweening;
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public enum TweenCancelBehaviour
{
Kill,
KillWithCompleteCallback,
Complete,
CompleteWithSeqeunceCallback,
CancelAwait,
// AndCancelAwait
KillAndCancelAwait,
KillWithCompleteCallbackAndCancelAwait,
CompleteAndCancelAwait,
CompleteWithSeqeunceCallbackAndCancelAwait
}
public static class DOTweenAsyncExtensions
{
enum CallbackType
{
Kill,
Complete,
Pause,
Play,
Rewind,
StepComplete
}
public static TweenAwaiter GetAwaiter(this Tween tween)
{
return new TweenAwaiter(tween);
}
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
}
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, 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
{
readonly Tween tween;
// killed(non active) as completed.
public bool IsCompleted => !tween.IsActive();
public TweenAwaiter(Tween tween)
{
this.tween = tween;
}
public TweenAwaiter GetAwaiter()
{
return this;
}
public void GetResult()
{
}
public void OnCompleted(System.Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(System.Action continuation)
{
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
tween.onKill = PooledTweenCallback.Create(continuation);
}
}
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
{
static TaskPool<TweenConfiguredSource> pool;
TweenConfiguredSource nextNode;
public ref TweenConfiguredSource NextNode => ref nextNode;
static TweenConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
}
static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onCompleteCallbackDelegate;
readonly TweenCallback onUpdateDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
CallbackType callbackType;
bool canceled;
TweenCallback originalUpdateAction;
UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource()
{
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
onUpdateDelegate = OnUpdate;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
DoCancelBeforeCreate(tween, cancelBehaviour);
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new TweenConfiguredSource();
}
result.tween = tween;
result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken;
result.callbackType = callbackType;
result.originalUpdateAction = tween.onUpdate;
result.canceled = false;
if (result.originalUpdateAction == result.onUpdateDelegate)
{
result.originalUpdateAction = null;
}
tween.onUpdate = result.onUpdateDelegate;
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);
token = result.core.Version;
return result;
}
void OnCompleteCallbackDelegate()
{
if (cancellationToken.IsCancellationRequested)
{
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
{
canceled = true;
}
}
if (canceled)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
}
void OnUpdate()
{
originalUpdateAction?.Invoke();
if (!cancellationToken.IsCancellationRequested)
{
return;
}
switch (this.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
this.canceled = true;
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
this.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
this.canceled = true;
this.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
this.canceled = true;
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
this.canceled = true;
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
// 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);
break;
}
}
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
{
switch (tweenCancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
break;
}
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
TryReturn();
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
tween.onUpdate = originalUpdateAction;
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;
cancellationToken = default;
originalUpdateAction = default;
return pool.TryPush(this);
}
}
}
sealed class PooledTweenCallback
{
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
readonly TweenCallback runDelegate;
Action continuation;
PooledTweenCallback()
{
runDelegate = Run;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TweenCallback Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new PooledTweenCallback();
}
item.continuation = continuation;
return item.runDelegate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.Enqueue(this);
call.Invoke();
}
}
}
}
#endif

View File

@@ -0,0 +1,22 @@
{
"name": "UniTask.DOTween",
"references": [
"UniTask",
"DOTween.Modules"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.demigiant.dotween",
"expression": "",
"define": "UNITASK_DOTWEEN_SUPPORT"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 029c1c1b674aaae47a6841a0b89ad80e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,290 +0,0 @@
// asmdef Version Defines, enabled when com.demigiant.dotween is imported.
#if UNITASK_DOTWEEN_SUPPORT
using Cysharp.Threading.Tasks.Internal;
using DG.Tweening;
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
// The idea of TweenCancelBehaviour is borrowed from https://www.shibuya24.info/entry/dotween_async_await
public enum TweenCancelBehaviour
{
Kill,
KillWithCompleteCallback,
Complete,
CompleteWithSeqeunceCallback,
CancelAwait,
// AndCancelAwait
KillAndCancelAwait,
KillWithCompleteCallbackAndCancelAwait,
CompleteAndCancelAwait,
CompleteWithSeqeunceCallbackAndCancelAwait
}
public static class DOTweenAsyncExtensions
{
public static TweenAwaiter GetAwaiter(this Tween tween)
{
return new TweenAwaiter(tween);
}
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, out var token), token);
}
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, out var token), token);
}
public struct TweenAwaiter : ICriticalNotifyCompletion
{
readonly Tween tween;
// killed(non active) as completed.
public bool IsCompleted => !tween.IsActive();
public TweenAwaiter(Tween tween)
{
this.tween = tween;
}
public TweenAwaiter GetAwaiter()
{
return this;
}
public void GetResult()
{
}
public void OnCompleted(System.Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(System.Action continuation)
{
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
tween.onKill = PooledTweenCallback.Create(continuation);
}
}
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
{
static TaskPool<TweenConfiguredSource> pool;
public TweenConfiguredSource NextNode { get; set; }
static TweenConfiguredSource()
{
TaskPoolMonitor.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
}
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onKillDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
bool canceled;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource()
{
onKillDelegate = OnKill;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new TweenConfiguredSource();
}
result.tween = tween;
result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
result.RegisterEvent();
token = result.core.Version;
return result;
}
void RegisterEvent()
{
if (cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
}
tween.OnKill(onKillDelegate);
}
void OnKill()
{
cancellationTokenRegistration.Dispose();
if (canceled)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
}
static void CancellationCallback(object state)
{
var self = (TweenConfiguredSource)state;
switch (self.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
self.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
self.canceled = true;
self.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
self.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
self.canceled = true;
self.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
self.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
self.canceled = true;
self.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
self.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
self.canceled = true;
self.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
self.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Caceled(instance is returned to pool.)
self.core.TrySetCanceled(self.cancellationToken);
break;
}
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
TryReturn();
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
tween = default;
cancellationToken = default;
return pool.TryPush(this);
}
~TweenConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
}
sealed class PooledTweenCallback
{
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
readonly TweenCallback runDelegate;
Action continuation;
PooledTweenCallback()
{
runDelegate = Run;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TweenCallback Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new PooledTweenCallback();
}
item.continuation = continuation;
return item.runDelegate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.Enqueue(this);
call.Invoke();
}
}
}
}
#endif

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f89da606bde9a4e4e94ae1189a029887
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,224 @@
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
}
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
}
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
}
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
}
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, false);
}
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken);
}
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, false);
}
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken);
}
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, false);
}
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, cancellationToken);
}
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, false);
}
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, cancellationToken);
}
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, false);
}
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, cancellationToken);
}
}
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4d5a9a3e1f0f069478969f752fde29a9 guid: 79f4f2475e0b2c44e97ed1dee760627b
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,66 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
var handlers = new (string name, string type)[] {
("ValueChanged", "string"),
("EndEdit", "string"),
("EndTextSelection", "(string, int, int)"),
("TextSelection", "(string, int, int)"),
("Deselect", "string"),
("Select", "string"),
("Submit", "string"),
};
Func<string, bool> shouldConvert = x => x.EndsWith("TextSelection");
Func<string, string> eventName = x => shouldConvert(x) ? $"new TextSelectionEventConverter(inputField.on{x})" : $"inputField.on{x}";
#>
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
<# foreach(var (name, type) in handlers) { #>
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, false);
}
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, cancellationToken);
}
<# } #>
}
}
#endif

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e9bb9fc551a975d44a7180e022a2debe
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
using UnityEngine.Events;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
// <string> -> Text
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> 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;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
// <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();
}
}
}
}
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: fcb1f7467a3e2b64c8a016c8aee2f9b4 guid: b6ba480edafb67d4e91bb10feb64fae5
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,22 @@
{
"name": "UniTask.TextMeshPro",
"references": [
"UniTask",
"Unity.TextMeshPro"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.textmeshpro",
"expression": "",
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dc47925d1a5fa2946bdd37746b2b5d48
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -19,7 +19,7 @@ namespace Cysharp.Threading.Tasks
// similar as IValueTaskSource // similar as IValueTaskSource
public interface IUniTaskSource public interface IUniTaskSource
#if !UNITY_2018_3_OR_NEWER #if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
: System.Threading.Tasks.Sources.IValueTaskSource : System.Threading.Tasks.Sources.IValueTaskSource
#pragma warning disable CS0108 #pragma warning disable CS0108
#endif #endif
@@ -30,7 +30,7 @@ namespace Cysharp.Threading.Tasks
UniTaskStatus UnsafeGetStatus(); // only for debug use. UniTaskStatus UnsafeGetStatus(); // only for debug use.
#if !UNITY_2018_3_OR_NEWER #if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#pragma warning restore CS0108 #pragma warning restore CS0108
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token) System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
@@ -53,13 +53,13 @@ namespace Cysharp.Threading.Tasks
} }
public interface IUniTaskSource<out T> : IUniTaskSource public interface IUniTaskSource<out T> : IUniTaskSource
#if !UNITY_2018_3_OR_NEWER #if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
, System.Threading.Tasks.Sources.IValueTaskSource<T> , System.Threading.Tasks.Sources.IValueTaskSource<T>
#endif #endif
{ {
new T GetResult(short token); new T GetResult(short token);
#if !UNITY_2018_3_OR_NEWER #if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
new public UniTaskStatus GetStatus(short token) new public UniTaskStatus GetStatus(short token)
{ {

View File

@@ -9,10 +9,10 @@ namespace Cysharp.Threading.Tasks.Internal
{ {
const int MaxArrayLength = 0X7FEFFFFF; const int MaxArrayLength = 0X7FEFFFFF;
const int InitialSize = 16; const int InitialSize = 16;
readonly PlayerLoopTiming timing; readonly PlayerLoopTiming timing;
SpinLock gate = new SpinLock(); SpinLock gate = new SpinLock(false);
bool dequing = false; bool dequing = false;
int actionListCount = 0; int actionListCount = 0;
@@ -70,13 +70,17 @@ namespace Cysharp.Threading.Tasks.Internal
} }
} }
public void Clear() public int Clear()
{ {
var rest = actionListCount + waitingListCount;
actionListCount = 0; actionListCount = 0;
actionList = new Action[InitialSize]; actionList = new Action[InitialSize];
waitingListCount = 0; waitingListCount = 0;
waitingList = new Action[InitialSize]; waitingList = new Action[InitialSize];
return rest;
} }
// delegate entrypoint. // delegate entrypoint.
@@ -128,6 +132,14 @@ namespace Cysharp.Threading.Tasks.Internal
case PlayerLoopTiming.LastPostLateUpdate: case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate(); LastPostLateUpdate();
break; break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
break;
case PlayerLoopTiming.LastTimeUpdate:
LastTimeUpdate();
break;
#endif
default: default:
break; break;
} }
@@ -150,6 +162,10 @@ namespace Cysharp.Threading.Tasks.Internal
void LastPreLateUpdate() => RunCore(); void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore(); void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore(); void LastPostLateUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore();
#endif
[System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerHidden]
void RunCore() void RunCore()
@@ -170,10 +186,17 @@ 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
action(); {
action();
}
catch (Exception ex)
{
UnityEngine.Debug.LogException(ex);
}
} }
{ {

View File

@@ -239,7 +239,7 @@ namespace Cysharp.Threading.Tasks.Internal
} }
else else
{ {
var fname = fi.FullName.Replace(Path.DirectorySeparatorChar, '/').Replace(Application.dataPath, ""); var fname = fi.FullName.Replace(Path.DirectorySeparatorChar, '/').Replace(PlayerLoopHelper.ApplicationDataPath, "");
var withAssetsPath = "Assets/" + fname; var withAssetsPath = "Assets/" + fname;
return "<a href=\"" + withAssetsPath + "\" line=\"" + line + "\">" + withAssetsPath + ":" + line + "</a>"; return "<a href=\"" + withAssetsPath + "\" line=\"" + line + "\">" + withAssetsPath + ":" + line + "</a>";
} }

View File

@@ -1,23 +0,0 @@
#if NET_4_6 || NET_STANDARD_2_0 || CSHARP_7_OR_LATER
using System;
namespace Cysharp.Threading.Tasks.Internal
{
internal static class FuncExtensions
{
// avoid lambda capture
internal static Action<T> AsFuncOfT<T>(this Action action)
{
return new Action<T>(action.Invoke);
}
static void Invoke<T>(this Action action, T unused)
{
action();
}
}
}
#endif

View File

@@ -48,14 +48,24 @@ namespace Cysharp.Threading.Tasks.Internal
} }
} }
public void Clear() public int Clear()
{ {
lock (arrayLock) lock (arrayLock)
{ {
var rest = 0;
for (var index = 0; index < loopItems.Length; index++) for (var index = 0; index < loopItems.Length; index++)
{ {
if (loopItems[index] != null)
{
rest++;
}
loopItems[index] = null; loopItems[index] = null;
} }
tail = 0;
return rest;
} }
} }
@@ -108,6 +118,14 @@ namespace Cysharp.Threading.Tasks.Internal
case PlayerLoopTiming.LastPostLateUpdate: case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate(); LastPostLateUpdate();
break; break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
break;
case PlayerLoopTiming.LastTimeUpdate:
LastTimeUpdate();
break;
#endif
default: default:
break; break;
} }
@@ -130,6 +148,10 @@ namespace Cysharp.Threading.Tasks.Internal
void LastPreLateUpdate() => RunCore(); void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore(); void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore(); void LastPostLateUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore();
#endif
[System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerHidden]
void RunCore() void RunCore()
@@ -143,7 +165,6 @@ namespace Cysharp.Threading.Tasks.Internal
{ {
var j = tail - 1; var j = tail - 1;
// eliminate array-bound check for i
for (int i = 0; i < loopItems.Length; i++) for (int i = 0; i < loopItems.Length; i++)
{ {
var action = loopItems[i]; var action = loopItems[i];

View File

@@ -7,11 +7,12 @@ 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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(PooledDelegate<T>), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(PooledDelegate<T>), () => pool.Size);
} }
readonly Action<T> runDelegate; readonly Action<T> runDelegate;

View File

@@ -60,9 +60,9 @@ namespace Cysharp.Threading.Tasks
#endif #endif
static List<KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>> listPool = new List<KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>>(); static List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>> listPool = new List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>>();
static readonly WeakDictionary<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)> tracking = new WeakDictionary<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>(); static readonly WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)> tracking = new WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>();
[Conditional("UNITY_EDITOR")] [Conditional("UNITY_EDITOR")]
public static void TrackActiveTask(IUniTaskSource task, int skipFrame) public static void TrackActiveTask(IUniTaskSource task, int skipFrame)
@@ -71,7 +71,19 @@ namespace Cysharp.Threading.Tasks
dirty = true; dirty = true;
if (!EditorEnableState.EnableTracking) return; if (!EditorEnableState.EnableTracking) return;
var stackTrace = EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, true).CleanupAsyncStackTrace() : ""; var stackTrace = EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, true).CleanupAsyncStackTrace() : "";
tracking.TryAdd(task, (Interlocked.Increment(ref trackingId), DateTime.UtcNow, stackTrace));
string typeName;
if (EditorEnableState.EnableStackTrace)
{
var sb = new StringBuilder();
TypeBeautify(task.GetType(), sb);
typeName = sb.ToString();
}
else
{
typeName = task.GetType().Name;
}
tracking.TryAdd(task, (typeName, Interlocked.Increment(ref trackingId), DateTime.UtcNow, stackTrace));
#endif #endif
} }
@@ -104,14 +116,8 @@ namespace Cysharp.Threading.Tasks
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
var keyType = listPool[i].Key.GetType(); action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
listPool[i] = default;
var sb = new StringBuilder();
TypeBeautify(keyType, sb);
var typeName = sb.ToString();
action(listPool[i].Value.trackingId, typeName, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
listPool[i] = new KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>(null, (0, default(DateTime), null)); // clear
} }
} }
catch catch
@@ -126,17 +132,31 @@ namespace Cysharp.Threading.Tasks
{ {
if (type.IsNested) if (type.IsNested)
{ {
TypeBeautify(type.DeclaringType, sb); // TypeBeautify(type.DeclaringType, sb);
sb.Append(type.DeclaringType.Name.ToString());
sb.Append("."); sb.Append(".");
} }
if (type.IsGenericType) if (type.IsGenericType)
{ {
var genericsStart = type.Name.IndexOf("`"); var genericsStart = type.Name.IndexOf("`");
sb.Append(type.Name.Substring(0, genericsStart)); if (genericsStart != -1)
{
sb.Append(type.Name.Substring(0, genericsStart));
}
else
{
sb.Append(type.Name);
}
sb.Append("<"); sb.Append("<");
var first = true;
foreach (var item in type.GetGenericArguments()) foreach (var item in type.GetGenericArguments())
{ {
if (!first)
{
sb.Append(", ");
}
first = false;
TypeBeautify(item, sb); TypeBeautify(item, sb);
} }
sb.Append(">"); sb.Append(">");
@@ -146,6 +166,13 @@ namespace Cysharp.Threading.Tasks
sb.Append(type.Name); sb.Append(type.Name);
} }
} }
//static string RemoveUniTaskNamespace(string str)
//{
// return str.Replace("Cysharp.Threading.Tasks.CompilerServices", "")
// .Replace("Cysharp.Threading.Tasks.Linq", "")
// .Replace("Cysharp.Threading.Tasks", "");
//}
} }
} }

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine.Networking;
namespace Cysharp.Threading.Tasks.Internal
{
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
internal static class UnityWebRequestResultExtensions
{
public static bool IsError(this UnityWebRequest unityWebRequest)
{
#if UNITY_2020_2_OR_NEWER
var result = unityWebRequest.result;
return (result == UnityWebRequest.Result.ConnectionError)
|| (result == UnityWebRequest.Result.DataProcessingError)
|| (result == UnityWebRequest.Result.ProtocolError);
#else
return unityWebRequest.isHttpError || unityWebRequest.isNetworkError;
#endif
}
}
#endif
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 111ba0e639de1d7428af6c823ead4918
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System;
using System.Diagnostics;
namespace Cysharp.Threading.Tasks.Internal
{
internal readonly struct ValueStopwatch
{
static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
readonly long startTimestamp;
public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());
ValueStopwatch(long startTimestamp)
{
this.startTimestamp = startTimestamp;
}
public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks);
public bool IsInvalid => startTimestamp == 0;
public long ElapsedTicks
{
get
{
if (startTimestamp == 0)
{
throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew().");
}
var delta = Stopwatch.GetTimestamp() - startTimestamp;
return (long)(delta * TimestampToTicks);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f16fb466974ad034c8732c79c7fd67ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,66 +3,9 @@ using System.Threading;
namespace Cysharp.Threading.Tasks.Linq namespace Cysharp.Threading.Tasks.Linq
{ {
public abstract class MoveNextSource : IUniTaskSource<bool> // note: refactor all inherit class and should remove this.
{ // see Select and Where.
protected UniTaskCompletionSourceCore<bool> completionSource; internal abstract class AsyncEnumeratorBase<TSource, TResult> : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
public bool GetResult(short token)
{
return completionSource.GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return completionSource.GetStatus(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
completionSource.OnCompleted(continuation, state, token);
}
public UniTaskStatus UnsafeGetStatus()
{
return completionSource.UnsafeGetStatus();
}
void IUniTaskSource.GetResult(short token)
{
completionSource.GetResult(token);
}
protected bool TryGetResult<T>(UniTask<T>.Awaiter awaiter, out T result)
{
try
{
result = awaiter.GetResult();
return true;
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
result = default;
return false;
}
}
protected bool TryGetResult(UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
return true;
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
return false;
}
}
}
public abstract class AsyncEnumeratorBase<TSource, TResult> : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack; static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack;
@@ -188,7 +131,7 @@ namespace Cysharp.Threading.Tasks.Linq
} }
} }
public abstract class AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TAwait> : MoveNextSource, IUniTaskAsyncEnumerator<TResult> internal abstract class AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TAwait> : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack; static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack;
static readonly Action<object> setCurrentCallbackDelegate = SetCurrentCallBack; static readonly Action<object> setCurrentCallbackDelegate = SetCurrentCallBack;
@@ -410,5 +353,4 @@ namespace Cysharp.Threading.Tasks.Linq
return default; return default;
} }
} }
} }

View File

@@ -0,0 +1,174 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<T> Create<T>(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
{
Error.ThrowArgumentNullException(create, nameof(create));
return new Create<T>(create);
}
}
public interface IAsyncWriter<T>
{
UniTask YieldAsync(T value);
}
internal sealed class Create<T> : IUniTaskAsyncEnumerable<T>
{
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
public Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
{
this.create = create;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Create(create, cancellationToken);
}
sealed class _Create : MoveNextSource, IUniTaskAsyncEnumerator<T>
{
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
readonly CancellationToken cancellationToken;
int state = -1;
AsyncWriter writer;
public _Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create, CancellationToken cancellationToken)
{
this.create = create;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
public T Current { get; private set; }
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return default;
}
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
{
writer = new AsyncWriter(this);
RunWriterTask(create(writer, cancellationToken)).Forget();
if (Volatile.Read(ref state) == -2)
{
return; // complete synchronously
}
state = 0; // wait YieldAsync, it set TrySetResult(true)
return;
}
case 0:
writer.SignalWriter();
return;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
}
async UniTaskVoid RunWriterTask(UniTask task)
{
try
{
await task;
goto DONE;
}
catch (Exception ex)
{
Volatile.Write(ref state, -2);
completionSource.TrySetException(ex);
return;
}
DONE:
Volatile.Write(ref state, -2);
completionSource.TrySetResult(false);
}
public void SetResult(T value)
{
Current = value;
completionSource.TrySetResult(true);
}
}
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
{
readonly _Create enumerator;
UniTaskCompletionSourceCore<AsyncUnit> core;
public AsyncWriter(_Create enumerator)
{
this.enumerator = enumerator;
}
public void GetResult(short token)
{
core.GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTask YieldAsync(T value)
{
core.Reset();
enumerator.SetResult(value);
return new UniTask(this, core.Version);
}
public void SignalWriter()
{
core.TrySetResult(AsyncUnit.Default);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0202f723469f93945afa063bfb440d15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -79,41 +79,123 @@ namespace Cysharp.Threading.Tasks.Linq
return new _DistinctUntilChanged(source, comparer, cancellationToken); return new _DistinctUntilChanged(source, comparer, cancellationToken);
} }
class _DistinctUntilChanged : AsyncEnumeratorBase<TSource, TSource> sealed class _DistinctUntilChanged : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly IEqualityComparer<TSource> comparer; readonly IEqualityComparer<TSource> comparer;
TSource prev; readonly CancellationToken cancellationToken;
bool first;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken) public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.comparer = comparer; this.comparer = comparer;
this.first = true; this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{ {
var v = SourceCurrent; switch (state)
if (first || !comparer.Equals(prev, v))
{ {
first = false; case -1: // init
Current = prev = v; enumerator = source.GetAsyncEnumerator(cancellationToken);
result = true; awaiter = enumerator.MoveNextAsync().GetAwaiter();
return true; if (awaiter.IsCompleted)
} {
else goto case -3;
{ }
result = default; else
return false; {
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
var v = enumerator.Current;
if (!comparer.Equals(Current, v))
{
Current = v;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
case -2:
default:
goto DONE;
} }
} }
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
result = false; DONE:
return true; state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
} }
} }
} }
@@ -136,45 +218,128 @@ namespace Cysharp.Threading.Tasks.Linq
return new _DistinctUntilChanged(source, keySelector, comparer, cancellationToken); return new _DistinctUntilChanged(source, keySelector, comparer, cancellationToken);
} }
class _DistinctUntilChanged : AsyncEnumeratorBase<TSource, TSource> sealed class _DistinctUntilChanged : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IEqualityComparer<TKey> comparer; readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, TKey> keySelector; readonly Func<TSource, TKey> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
TKey prev; TKey prev;
bool first;
public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken) public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.comparer = comparer; this.source = source;
this.keySelector = keySelector; this.keySelector = keySelector;
this.first = true; this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{ {
var v = SourceCurrent; switch (state)
var key = keySelector(v);
if (first || !comparer.Equals(prev, key))
{ {
first = false; case -1: // init
prev = key; enumerator = source.GetAsyncEnumerator(cancellationToken);
Current = v; awaiter = enumerator.MoveNextAsync().GetAwaiter();
result = true; if (awaiter.IsCompleted)
return true; {
} goto case -3;
else }
{ else
result = default; {
return false; state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
var v = enumerator.Current;
var key = keySelector(v);
if (!comparer.Equals(prev, key))
{
prev = key;
Current = v;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
case -2:
default:
goto DONE;
} }
} }
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
result = false; DONE:
return true; state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
} }
} }
} }
@@ -197,42 +362,142 @@ namespace Cysharp.Threading.Tasks.Linq
return new _DistinctUntilChangedAwait(source, keySelector, comparer, cancellationToken); return new _DistinctUntilChangedAwait(source, keySelector, comparer, cancellationToken);
} }
class _DistinctUntilChangedAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey> sealed class _DistinctUntilChangedAwait : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IEqualityComparer<TKey> comparer; readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, UniTask<TKey>> keySelector; readonly Func<TSource, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TKey>.Awaiter awaiter2;
Action moveNextAction;
TSource enumeratorCurrent;
TKey prev; TKey prev;
bool first;
public _DistinctUntilChangedAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken) public _DistinctUntilChangedAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.comparer = comparer; this.source = source;
this.keySelector = keySelector; this.keySelector = keySelector;
this.first = true; this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
} }
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return keySelector(sourceCurrent); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TKey key, out bool terminateIteration) void MoveNext()
{ {
if (first || !comparer.Equals(prev, key)) REPEAT:
try
{ {
first = false; switch (state)
prev = key; {
Current = SourceCurrent; case -1: // init
terminateIteration = false; enumerator = source.GetAsyncEnumerator(cancellationToken);
return true; awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
enumeratorCurrent = enumerator.Current;
awaiter2 = keySelector(enumeratorCurrent).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
var key = awaiter2.GetResult();
if (!comparer.Equals(prev, key))
{
prev = key;
Current = enumeratorCurrent;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
case -2:
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
terminateIteration = false; state = -2;
return false; completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
} }
} }
} }
@@ -255,42 +520,142 @@ namespace Cysharp.Threading.Tasks.Linq
return new _DistinctUntilChangedAwaitWithCancellation(source, keySelector, comparer, cancellationToken); return new _DistinctUntilChangedAwaitWithCancellation(source, keySelector, comparer, cancellationToken);
} }
class _DistinctUntilChangedAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey> sealed class _DistinctUntilChangedAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IEqualityComparer<TKey> comparer; readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector; readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TKey>.Awaiter awaiter2;
Action moveNextAction;
TSource enumeratorCurrent;
TKey prev; TKey prev;
bool first;
public _DistinctUntilChangedAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken) public _DistinctUntilChangedAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.comparer = comparer; this.source = source;
this.keySelector = keySelector; this.keySelector = keySelector;
this.first = true; this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
} }
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return keySelector(sourceCurrent, cancellationToken); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TKey key, out bool terminateIteration) void MoveNext()
{ {
if (first || !comparer.Equals(prev, key)) REPEAT:
try
{ {
first = false; switch (state)
prev = key; {
Current = SourceCurrent; case -1: // init
terminateIteration = false; enumerator = source.GetAsyncEnumerator(cancellationToken);
return true; awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
enumeratorCurrent = enumerator.Current;
awaiter2 = keySelector(enumeratorCurrent, cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
var key = awaiter2.GetResult();
if (!comparer.Equals(prev, key))
{
prev = key;
Current = enumeratorCurrent;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
case -2:
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
terminateIteration = false; state = -2;
return false; completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
} }
} }
} }

View File

@@ -115,6 +115,8 @@ namespace Cysharp.Threading.Tasks.Linq
} }
public TSource Current { get; private set; } public TSource Current { get; private set; }
ITriggerHandler<TSource> ITriggerHandler<TSource>.Prev { get; set; }
ITriggerHandler<TSource> ITriggerHandler<TSource>.Next { get; set; }
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {

View File

@@ -71,29 +71,94 @@ namespace Cysharp.Threading.Tasks.Linq
return new _Select(source, selector, cancellationToken); return new _Select(source, selector, cancellationToken);
} }
sealed class _Select : AsyncEnumeratorBase<TSource, TResult> sealed class _Select : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, TResult> selector; readonly Func<TSource, TResult> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
public _Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken) public _Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{ {
Current = selector(SourceCurrent); switch (state)
result = true; {
return true; case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = selector(enumerator.Current);
goto CONTINUE;
}
else
{
goto DONE;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
result = false; state = -2;
return true; completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -111,33 +176,98 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _SelectInt(source, selector, cancellationToken); return new _Select(source, selector, cancellationToken);
} }
sealed class _SelectInt : AsyncEnumeratorBase<TSource, TResult> sealed class _Select : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, TResult> selector; readonly Func<TSource, int, TResult> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
int index; int index;
public _SelectInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, CancellationToken cancellationToken) public _Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{ {
Current = selector(SourceCurrent, checked(index++)); switch (state)
result = true; {
return true; case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = selector(enumerator.Current, checked(index++));
goto CONTINUE;
}
else
{
goto DONE;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
result = false; state = -2;
return true; completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -158,26 +288,107 @@ namespace Cysharp.Threading.Tasks.Linq
return new _SelectAwait(source, selector, cancellationToken); return new _SelectAwait(source, selector, cancellationToken);
} }
sealed class _SelectAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult> sealed class _SelectAwait : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, UniTask<TResult>> selector; readonly Func<TSource, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
public _SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken) public _SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return selector(sourceCurrent); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration) void MoveNext()
{ {
Current = awaitResult; try
terminateIteration = false; {
return true; switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -195,30 +406,111 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _SelectIntAwait(source, selector, cancellationToken); return new _SelectAwait(source, selector, cancellationToken);
} }
sealed class _SelectIntAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult> sealed class _SelectAwait : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, UniTask<TResult>> selector; readonly Func<TSource, int, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
int index; int index;
public _SelectIntAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector, CancellationToken cancellationToken) public _SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return selector(sourceCurrent, checked(index++)); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration) void MoveNext()
{ {
Current = awaitResult; try
terminateIteration = false; {
return true; switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, checked(index++)).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -239,26 +531,107 @@ namespace Cysharp.Threading.Tasks.Linq
return new _SelectAwaitWithCancellation(source, selector, cancellationToken); return new _SelectAwaitWithCancellation(source, selector, cancellationToken);
} }
sealed class _SelectAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult> sealed class _SelectAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TResult>> selector; readonly Func<TSource, CancellationToken, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
public _SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken) public _SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return selector(sourceCurrent, cancellationToken); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration) void MoveNext()
{ {
Current = awaitResult; try
terminateIteration = false; {
return true; switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -276,32 +649,112 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _SelectIntAwaitWithCancellation(source, selector, cancellationToken); return new _SelectAwaitWithCancellation(source, selector, cancellationToken);
} }
sealed class _SelectIntAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult> sealed class _SelectAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector; readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
int index; int index;
public _SelectIntAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken) public _SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.selector = selector; this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent) public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return selector(sourceCurrent, checked(index++), cancellationToken); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration) void MoveNext()
{ {
Current = awaitResult; try
terminateIteration = false; {
return true; switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, checked(index++), cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
} }

View File

@@ -0,0 +1,187 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
{
Error.ThrowArgumentNullException(source, nameof(source));
return new SkipUntil<TSource>(source, other, null);
}
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(other));
return new SkipUntil<TSource>(source, default, other);
}
}
internal sealed class SkipUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly UniTask other;
readonly Func<CancellationToken, UniTask> other2;
public SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
{
this.source = source;
this.other = other;
this.other2 = other2;
}
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
if (other2 != null)
{
return new _SkipUntil(source, this.other2(cancellationToken), cancellationToken);
}
else
{
return new _SkipUntil(source, this.other, cancellationToken);
}
}
sealed class _SkipUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
static readonly Action<object> CancelDelegate1 = OnCanceled1;
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken1;
bool completed;
CancellationTokenRegistration cancellationTokenRegistration1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
bool continueNext;
Exception exception;
public _SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
{
this.source = source;
this.cancellationToken1 = cancellationToken1;
if (cancellationToken1.CanBeCanceled)
{
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
}
TaskTracker.TrackActiveTask(this, 3);
RunOther(other).Forget();
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (exception != null)
{
return UniTask.FromException<bool>(exception);
}
if (cancellationToken1.IsCancellationRequested)
{
return UniTask.FromCanceled<bool>(cancellationToken1);
}
if (enumerator == null)
{
enumerator = source.GetAsyncEnumerator(cancellationToken1);
}
completionSource.Reset();
if (completed)
{
SourceMoveNext();
}
return new UniTask<bool>(this, completionSource.Version);
}
void SourceMoveNext()
{
try
{
LOOP:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
continueNext = true;
MoveNextCore(this);
if (continueNext)
{
continueNext = false;
goto LOOP;
}
}
else
{
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
}
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void MoveNextCore(object state)
{
var self = (_SkipUntil)state;
if (self.TryGetResult(self.awaiter, out var result))
{
if (result)
{
self.Current = self.enumerator.Current;
self.completionSource.TrySetResult(true);
if (self.continueNext)
{
self.SourceMoveNext();
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
async UniTaskVoid RunOther(UniTask other)
{
try
{
await other;
completed = true;
SourceMoveNext();
}
catch (Exception ex)
{
exception = ex;
completionSource.TrySetException(ex);
}
}
static void OnCanceled1(object state)
{
var self = (_SkipUntil)state;
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
cancellationTokenRegistration1.Dispose();
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de932d79c8d9f3841a066d05ff29edc9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -32,13 +32,17 @@ namespace Cysharp.Threading.Tasks.Linq
sealed class _SkipUntilCanceled : MoveNextSource, IUniTaskAsyncEnumerator<TSource> sealed class _SkipUntilCanceled : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
static readonly Action<object> CancelDelegate1 = OnCanceled1;
static readonly Action<object> CancelDelegate2 = OnCanceled2;
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore; static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
readonly IUniTaskAsyncEnumerable<TSource> source; readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken1; CancellationToken cancellationToken1;
CancellationToken cancellationToken2; CancellationToken cancellationToken2;
CancellationTokenRegistration cancellationTokenRegistration1;
CancellationTokenRegistration cancellationTokenRegistration2;
bool isCanceled; int isCanceled;
IUniTaskAsyncEnumerator<TSource> enumerator; IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter; UniTask<bool>.Awaiter awaiter;
bool continueNext; bool continueNext;
@@ -48,6 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
this.source = source; this.source = source;
this.cancellationToken1 = cancellationToken1; this.cancellationToken1 = cancellationToken1;
this.cancellationToken2 = cancellationToken2; this.cancellationToken2 = cancellationToken2;
if (cancellationToken1.CanBeCanceled)
{
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
}
if (cancellationToken1 != cancellationToken2 && cancellationToken2.CanBeCanceled)
{
this.cancellationTokenRegistration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(CancelDelegate2, this);
}
TaskTracker.TrackActiveTask(this, 3); TaskTracker.TrackActiveTask(this, 3);
} }
@@ -55,15 +67,18 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {
if (cancellationToken1.IsCancellationRequested) isCanceled = true;
if (cancellationToken2.IsCancellationRequested) isCanceled = true;
if (enumerator == null) if (enumerator == null)
{ {
if (cancellationToken1.IsCancellationRequested) isCanceled = 1;
if (cancellationToken2.IsCancellationRequested) isCanceled = 1;
enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token. enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token.
} }
completionSource.Reset(); completionSource.Reset();
SourceMoveNext();
if (isCanceled != 0)
{
SourceMoveNext();
}
return new UniTask<bool>(this, completionSource.Version); return new UniTask<bool>(this, completionSource.Version);
} }
@@ -102,25 +117,11 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
if (result) if (result)
{ {
AGAIN: self.Current = self.enumerator.Current;
self.completionSource.TrySetResult(true);
if (self.isCanceled) if (self.continueNext)
{ {
self.continueNext = false; self.SourceMoveNext();
self.Current = self.enumerator.Current;
self.completionSource.TrySetResult(true);
}
else
{
if (self.cancellationToken1.IsCancellationRequested) self.isCanceled = true;
if (self.cancellationToken2.IsCancellationRequested) self.isCanceled = true;
if (self.isCanceled) goto AGAIN;
if (!self.continueNext)
{
self.SourceMoveNext();
}
} }
} }
else else
@@ -130,9 +131,37 @@ namespace Cysharp.Threading.Tasks.Linq
} }
} }
static void OnCanceled1(object state)
{
var self = (_SkipUntilCanceled)state;
if (self.isCanceled == 0)
{
if (Interlocked.Increment(ref self.isCanceled) == 1)
{
self.cancellationTokenRegistration2.Dispose();
self.SourceMoveNext();
}
}
}
static void OnCanceled2(object state)
{
var self = (_SkipUntilCanceled)state;
if (self.isCanceled == 0)
{
if (Interlocked.Increment(ref self.isCanceled) == 1)
{
self.cancellationTokenRegistration2.Dispose();
self.SourceMoveNext();
}
}
}
public UniTask DisposeAsync() public UniTask DisposeAsync()
{ {
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
cancellationTokenRegistration1.Dispose();
cancellationTokenRegistration2.Dispose();
if (enumerator != null) if (enumerator != null)
{ {
return enumerator.DisposeAsync(); return enumerator.DisposeAsync();

View File

@@ -0,0 +1,536 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
using Subscribes = Cysharp.Threading.Tasks.Linq.Subscribe;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
// OnNext
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
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
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
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
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
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
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(observer, nameof(observer));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, observer, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(observer, nameof(observer));
Subscribes.SubscribeCore(source, observer, cancellationToken).Forget();
}
}
internal sealed class CancellationTokenDisposable : IDisposable
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
public CancellationToken Token => cts.Token;
public void Dispose()
{
if (!cts.IsCancellationRequested)
{
cts.Cancel();
}
}
}
internal static class Subscribe
{
public static readonly Action<Exception> NopError = _ => { };
public static readonly Action NopCompleted = () => { };
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
try
{
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 SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
try
{
onNext(e.Current).Forget();
}
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 SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
try
{
onNext(e.Current, cancellationToken).Forget();
}
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 SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
try
{
observer.OnNext(e.Current);
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
}
observer.OnCompleted();
}
catch (Exception ex)
{
if (ex is OperationCanceledException) return;
observer.OnError(ex);
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 263479eb04c189741931fc0e2f615c2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
{
Error.ThrowArgumentNullException(source, nameof(source));
return new TakeUntil<TSource>(source, other, null);
}
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(other));
return new TakeUntil<TSource>(source, default, other);
}
}
internal sealed class TakeUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly UniTask other;
readonly Func<CancellationToken, UniTask> other2;
public TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
{
this.source = source;
this.other = other;
this.other2 = other2;
}
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
if (other2 != null)
{
return new _TakeUntil(source, this.other2(cancellationToken), cancellationToken);
}
else
{
return new _TakeUntil(source, this.other, cancellationToken);
}
}
sealed class _TakeUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
static readonly Action<object> CancelDelegate1 = OnCanceled1;
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken1;
CancellationTokenRegistration cancellationTokenRegistration1;
bool completed;
Exception exception;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
public _TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
{
this.source = source;
this.cancellationToken1 = cancellationToken1;
if (cancellationToken1.CanBeCanceled)
{
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
}
TaskTracker.TrackActiveTask(this, 3);
RunOther(other).Forget();
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (completed)
{
return CompletedTasks.False;
}
if (exception != null)
{
return UniTask.FromException<bool>(exception);
}
if (cancellationToken1.IsCancellationRequested)
{
return UniTask.FromCanceled<bool>(cancellationToken1);
}
if (enumerator == null)
{
enumerator = source.GetAsyncEnumerator(cancellationToken1);
}
completionSource.Reset();
SourceMoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void SourceMoveNext()
{
try
{
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
MoveNextCore(this);
}
else
{
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
}
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void MoveNextCore(object state)
{
var self = (_TakeUntil)state;
if (self.TryGetResult(self.awaiter, out var result))
{
if (result)
{
if (self.exception != null)
{
self.completionSource.TrySetException(self.exception);
}
else if (self.cancellationToken1.IsCancellationRequested)
{
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
else
{
self.Current = self.enumerator.Current;
self.completionSource.TrySetResult(true);
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
async UniTaskVoid RunOther(UniTask other)
{
try
{
await other;
completed = true;
completionSource.TrySetResult(false);
}
catch (Exception ex)
{
exception = ex;
completionSource.TrySetException(ex);
}
}
static void OnCanceled1(object state)
{
var self = (_TakeUntil)state;
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
cancellationTokenRegistration1.Dispose();
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12bda324162f15349afefc2c152ac07f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -248,15 +248,18 @@ namespace Cysharp.Threading.Tasks.Linq
return current; return current;
} }
if (queuedResult.Count != 0) lock (queuedResult)
{ {
current = queuedResult.Dequeue(); if (queuedResult.Count != 0)
useCachedCurrent = true; {
return current; current = queuedResult.Dequeue();
} useCachedCurrent = true;
else return current;
{ }
return default; // undefined. else
{
return default; // undefined.
}
} }
} }
} }

View File

@@ -0,0 +1,15 @@
{
"name": "UniTask.Linq",
"references": [
"UniTask"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5c01796d064528144a599661eaab93a6
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -34,6 +34,7 @@ namespace Cysharp.Threading.Tasks.Linq
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken) public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
{ {
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);

View File

@@ -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);

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Threading; using System.Threading;
using UnityEngine;
namespace Cysharp.Threading.Tasks.Linq namespace Cysharp.Threading.Tasks.Linq
{ {
@@ -22,16 +23,34 @@ namespace Cysharp.Threading.Tasks.Linq
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
{ {
if (dueTimeFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, null, updateTiming); return new TimerFrame(dueTimeFrameCount, null, updateTiming);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
{ {
if (dueTimeFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
}
if (periodFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming); return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
{ {
if (intervalFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus intervalFrameCount. intervalFrameCount:" + intervalFrameCount);
}
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming); return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming);
} }
} }
@@ -64,6 +83,7 @@ namespace Cysharp.Threading.Tasks.Linq
readonly bool ignoreTimeScale; readonly bool ignoreTimeScale;
CancellationToken cancellationToken; CancellationToken cancellationToken;
int initialFrame;
float elapsed; float elapsed;
bool dueTimePhase; bool dueTimePhase;
bool completed; bool completed;
@@ -80,9 +100,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (this.period <= 0) this.period = 1; if (this.period <= 0) this.period = 1;
} }
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
this.dueTimePhase = true; this.dueTimePhase = true;
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale; this.ignoreTimeScale = ignoreTimeScale;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);
} }
@@ -119,9 +141,19 @@ namespace Cysharp.Threading.Tasks.Linq
return false; return false;
} }
elapsed += (ignoreTimeScale) ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
if (dueTimePhase) if (dueTimePhase)
{ {
if (elapsed == 0)
{
// skip in initial frame.
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += (ignoreTimeScale) ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
if (elapsed >= dueTime) if (elapsed >= dueTime)
{ {
dueTimePhase = false; dueTimePhase = false;
@@ -137,6 +169,8 @@ namespace Cysharp.Threading.Tasks.Linq
return false; return false;
} }
elapsed += (ignoreTimeScale) ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
if (elapsed >= period) if (elapsed >= period)
{ {
completionSource.TrySetResult(true); completionSource.TrySetResult(true);
@@ -172,6 +206,7 @@ namespace Cysharp.Threading.Tasks.Linq
readonly int? periodFrameCount; readonly int? periodFrameCount;
CancellationToken cancellationToken; CancellationToken cancellationToken;
int initialFrame;
int currentFrame; int currentFrame;
bool dueTimePhase; bool dueTimePhase;
bool completed; bool completed;
@@ -185,9 +220,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (periodFrameCount <= 0) periodFrameCount = 1; if (periodFrameCount <= 0) periodFrameCount = 1;
} }
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
this.dueTimePhase = true; this.dueTimePhase = true;
this.dueTimeFrameCount = dueTimeFrameCount; this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount; this.periodFrameCount = periodFrameCount;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);
@@ -228,11 +265,30 @@ namespace Cysharp.Threading.Tasks.Linq
if (dueTimePhase) if (dueTimePhase)
{ {
if (currentFrame++ >= dueTimeFrameCount) if (currentFrame == 0)
{
if (dueTimeFrameCount == 0)
{
dueTimePhase = false;
completionSource.TrySetResult(true);
return true;
}
// skip in initial frame.
if (initialFrame == Time.frameCount)
{
return true;
}
}
if (++currentFrame >= dueTimeFrameCount)
{ {
dueTimePhase = false; dueTimePhase = false;
completionSource.TrySetResult(true); completionSource.TrySetResult(true);
} }
else
{
}
} }
else else
{ {

View File

@@ -71,36 +71,103 @@ namespace Cysharp.Threading.Tasks.Linq
return new _Where(source, predicate, cancellationToken); return new _Where(source, predicate, cancellationToken);
} }
class _Where : AsyncEnumeratorBase<TSource, TSource> sealed class _Where : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, bool> predicate; readonly Func<TSource, bool> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
public _Where(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken) public _Where(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{ {
if (predicate(SourceCurrent)) switch (state)
{ {
Current = SourceCurrent; case -1: // init
result = true; enumerator = source.GetAsyncEnumerator(cancellationToken);
return true; goto case 0;
} case 0:
else awaiter = enumerator.MoveNextAsync().GetAwaiter();
{ if (awaiter.IsCompleted)
result = default; {
return false; goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
if (predicate(Current))
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
default:
goto DONE;
} }
} }
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
result = false; DONE:
return true; state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -118,40 +185,107 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _WhereInt(source, predicate, cancellationToken); return new _Where(source, predicate, cancellationToken);
} }
class _WhereInt : AsyncEnumeratorBase<TSource, TSource> sealed class _Where : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, bool> predicate; readonly Func<TSource, int, bool> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
int index; int index;
public _WhereInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, CancellationToken cancellationToken) public _Where(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
if (sourceHasCurrent) if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{ {
if (predicate(SourceCurrent, checked(index++))) switch (state)
{ {
Current = SourceCurrent; case -1: // init
result = true; enumerator = source.GetAsyncEnumerator(cancellationToken);
return true; goto case 0;
} case 0:
else awaiter = enumerator.MoveNextAsync().GetAwaiter();
{ if (awaiter.IsCompleted)
result = default; {
return false; goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
if (predicate(Current, checked(index++)))
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
default:
goto DONE;
} }
} }
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
result = false; DONE:
return true; state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -172,34 +306,117 @@ namespace Cysharp.Threading.Tasks.Linq
return new _WhereAwait(source, predicate, cancellationToken); return new _WhereAwait(source, predicate, cancellationToken);
} }
class _WhereAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool> sealed class _WhereAwait : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, UniTask<bool>> predicate; readonly Func<TSource, UniTask<bool>> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<bool>.Awaiter awaiter2;
Action moveNextAction;
public _WhereAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate, CancellationToken cancellationToken) public _WhereAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<bool> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return predicate(sourceCurrent); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration) void MoveNext()
{ {
terminateIteration = false; REPEAT:
if (awaitResult) try
{ {
Current = SourceCurrent; switch (state)
return true; {
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
awaiter2 = predicate(Current).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
if (awaiter2.GetResult())
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
return false; state = -2;
completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -217,44 +434,125 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _WhereIntAwait(source, predicate, cancellationToken); return new _WhereAwait(source, predicate, cancellationToken);
} }
class _WhereIntAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool> sealed class _WhereAwait : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, UniTask<bool>> predicate; readonly Func<TSource, int, UniTask<bool>> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<bool>.Awaiter awaiter2;
Action moveNextAction;
int index; int index;
public _WhereIntAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate, CancellationToken cancellationToken) public _WhereAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<bool> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return predicate(sourceCurrent, checked(index++)); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration) void MoveNext()
{ {
terminateIteration = false; REPEAT:
if (awaitResult) try
{ {
Current = SourceCurrent; switch (state)
return true; {
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
awaiter2 = predicate(Current, checked(index++)).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
if (awaiter2.GetResult())
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
return false; state = -2;
completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
internal sealed class WhereAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource> internal sealed class WhereAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source; readonly IUniTaskAsyncEnumerable<TSource> source;
@@ -271,34 +569,117 @@ namespace Cysharp.Threading.Tasks.Linq
return new _WhereAwaitWithCancellation(source, predicate, cancellationToken); return new _WhereAwaitWithCancellation(source, predicate, cancellationToken);
} }
class _WhereAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool> sealed class _WhereAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<bool>> predicate; readonly Func<TSource, CancellationToken, UniTask<bool>> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<bool>.Awaiter awaiter2;
Action moveNextAction;
public _WhereAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken) public _WhereAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<bool> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return predicate(sourceCurrent, cancellationToken); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration) void MoveNext()
{ {
terminateIteration = false; REPEAT:
if (awaitResult) try
{ {
Current = SourceCurrent; switch (state)
return true; {
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
awaiter2 = predicate(Current, cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
if (awaiter2.GetResult())
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
return false; state = -2;
completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
@@ -316,40 +697,122 @@ namespace Cysharp.Threading.Tasks.Linq
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _WhereIntAwaitWithCancellation(source, predicate, cancellationToken); return new _WhereAwaitWithCancellation(source, predicate, cancellationToken);
} }
class _WhereIntAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool> sealed class _WhereAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{ {
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate; readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<bool>.Awaiter awaiter2;
Action moveNextAction;
int index; int index;
public _WhereIntAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken) public _WhereAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
: base(source, cancellationToken)
{ {
this.source = source;
this.predicate = predicate; this.predicate = predicate;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
} }
protected override UniTask<bool> TransformAsync(TSource sourceCurrent) public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{ {
return predicate(sourceCurrent, checked(index++), cancellationToken); if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
} }
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration) void MoveNext()
{ {
terminateIteration = false; REPEAT:
if (awaitResult) try
{ {
Current = SourceCurrent; switch (state)
return true; {
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = enumerator.Current;
awaiter2 = predicate(Current, checked(index++), cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
if (awaiter2.GetResult())
{
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
default:
goto DONE;
}
} }
else catch (Exception ex)
{ {
return false; state = -2;
completionSource.TrySetException(ex);
return;
} }
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
} }
} }
} }
} }

View File

@@ -0,0 +1,63 @@
using System;
namespace Cysharp.Threading.Tasks
{
public abstract class MoveNextSource : IUniTaskSource<bool>
{
protected UniTaskCompletionSourceCore<bool> completionSource;
public bool GetResult(short token)
{
return completionSource.GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return completionSource.GetStatus(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
completionSource.OnCompleted(continuation, state, token);
}
public UniTaskStatus UnsafeGetStatus()
{
return completionSource.UnsafeGetStatus();
}
void IUniTaskSource.GetResult(short token)
{
completionSource.GetResult(token);
}
protected bool TryGetResult<T>(UniTask<T>.Awaiter awaiter, out T result)
{
try
{
result = awaiter.GetResult();
return true;
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
result = default;
return false;
}
}
protected bool TryGetResult(UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
return true;
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
return false;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc4c5dc2a5f246e4f8df44cab735826c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,8 +8,10 @@ using System.Threading;
#if UNITY_2019_3_OR_NEWER #if UNITY_2019_3_OR_NEWER
using UnityEngine.LowLevel; using UnityEngine.LowLevel;
using PlayerLoopType = UnityEngine.PlayerLoop;
#else #else
using UnityEngine.Experimental.LowLevel; using UnityEngine.Experimental.LowLevel;
using PlayerLoopType = UnityEngine.Experimental.PlayerLoop;
#endif #endif
#if UNITY_EDITOR #if UNITY_EDITOR
@@ -57,6 +59,13 @@ namespace Cysharp.Threading.Tasks
public struct UniTaskLoopRunnerLastYieldUpdate { }; public struct UniTaskLoopRunnerLastYieldUpdate { };
public struct UniTaskLoopRunnerLastYieldPreLateUpdate { }; public struct UniTaskLoopRunnerLastYieldPreLateUpdate { };
public struct UniTaskLoopRunnerLastYieldPostLateUpdate { }; public struct UniTaskLoopRunnerLastYieldPostLateUpdate { };
#if UNITY_2020_2_OR_NEWER
public struct UniTaskLoopRunnerTimeUpdate { };
public struct UniTaskLoopRunnerLastTimeUpdate { };
public struct UniTaskLoopRunnerYieldTimeUpdate { };
public struct UniTaskLoopRunnerLastYieldTimeUpdate { };
#endif
} }
public enum PlayerLoopTiming public enum PlayerLoopTiming
@@ -80,7 +89,13 @@ namespace Cysharp.Threading.Tasks
LastPreLateUpdate = 11, LastPreLateUpdate = 11,
PostLateUpdate = 12, PostLateUpdate = 12,
LastPostLateUpdate = 13 LastPostLateUpdate = 13,
#if UNITY_2020_2_OR_NEWER
// Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
TimeUpdate = 14,
LastTimeUpdate = 15,
#endif
} }
public interface IPlayerLoopItem public interface IPlayerLoopItem
@@ -92,12 +107,16 @@ namespace Cysharp.Threading.Tasks
{ {
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext; public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext;
public static int MainThreadId => mainThreadId; public static int MainThreadId => mainThreadId;
internal static string ApplicationDataPath => applicationDataPath;
public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;
static int mainThreadId; static int mainThreadId;
static string applicationDataPath;
static SynchronizationContext unitySynchronizationContetext; static SynchronizationContext unitySynchronizationContetext;
static ContinuationQueue[] yielders; static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners; static PlayerLoopRunner[] runners;
internal static bool IsEditorApplicationQuitting { get; private set; }
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
Type loopRunnerYieldType, ContinuationQueue cq, Type lastLoopRunnerYieldType, ContinuationQueue lastCq, Type loopRunnerYieldType, ContinuationQueue cq, Type lastLoopRunnerYieldType, ContinuationQueue lastCq,
Type loopRunnerType, PlayerLoopRunner runner, Type lastLoopRunnerType, PlayerLoopRunner lastRunner) Type loopRunnerType, PlayerLoopRunner runner, Type lastLoopRunnerType, PlayerLoopRunner lastRunner)
@@ -106,27 +125,32 @@ namespace Cysharp.Threading.Tasks
#if UNITY_EDITOR #if UNITY_EDITOR
EditorApplication.playModeStateChanged += (state) => EditorApplication.playModeStateChanged += (state) =>
{ {
if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode) if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.ExitingEditMode)
{ {
return; IsEditorApplicationQuitting = true;
} // run rest action before clear.
if (runner != null)
{
runner.Run();
runner.Clear();
}
if (lastRunner != null)
{
lastRunner.Run();
lastRunner.Clear();
}
if (runner != null) if (cq != null)
{ {
runner.Clear(); cq.Run();
} cq.Clear();
if (lastRunner != null) }
{ if (lastCq != null)
lastRunner.Clear(); {
} lastCq.Run();
lastCq.Clear();
if (cq != null) }
{ IsEditorApplicationQuitting = false;
cq.Clear();
}
if (lastCq != null)
{
lastCq.Clear();
} }
}; };
#endif #endif
@@ -171,12 +195,43 @@ namespace Cysharp.Threading.Tasks
return dest; return dest;
} }
static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
{
var loop = new PlayerLoopSystem
{
type = typeof(UniTaskSynchronizationContext),
updateDelegate = UniTaskSynchronizationContext.Run
};
// Remove items from previous initializations.
var source = loopSystem.subSystemList
.Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
.ToArray();
var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
if (index == -1)
{
index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
}
dest.Insert(index + 1, loop);
return dest.ToArray();
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Init() static void Init()
{ {
// capture default(unity) sync-context. // capture default(unity) sync-context.
unitySynchronizationContetext = SynchronizationContext.Current; unitySynchronizationContetext = SynchronizationContext.Current;
mainThreadId = Thread.CurrentThread.ManagedThreadId; mainThreadId = Thread.CurrentThread.ManagedThreadId;
try
{
applicationDataPath = Application.dataPath;
}
catch { }
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER #if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
// When domain reload is disabled, re-initialization is required when entering play mode; // When domain reload is disabled, re-initialization is required when entering play mode;
@@ -237,52 +292,90 @@ namespace Cysharp.Threading.Tasks
if (item != null) item.Run(); if (item != null) item.Run();
} }
} }
UniTaskSynchronizationContext.Run();
} }
#endif #endif
private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
{
for (int i = 0; i < playerLoopList.Length; i++)
{
if (playerLoopList[i].type == systemType)
{
return i;
}
}
throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
}
public static void Initialize(ref PlayerLoopSystem playerLoop) public static void Initialize(ref PlayerLoopSystem playerLoop)
{ {
#if UNITY_2020_2_OR_NEWER
yielders = new ContinuationQueue[16];
runners = new PlayerLoopRunner[16];
#else
yielders = new ContinuationQueue[14]; yielders = new ContinuationQueue[14];
runners = new PlayerLoopRunner[14]; runners = new PlayerLoopRunner[14];
#endif
var copyList = playerLoop.subSystemList.ToArray(); var copyList = playerLoop.subSystemList.ToArray();
// Initialization var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Initialization));
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization), copyList[i].subSystemList = InsertRunner(copyList[i], 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), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.EarlyUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), yielders[3] = new ContinuationQueue(PlayerLoopTiming.LastEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), yielders[3] = new ContinuationQueue(PlayerLoopTiming.LastEarlyUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[2] = new PlayerLoopRunner(PlayerLoopTiming.EarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[2] = new PlayerLoopRunner(PlayerLoopTiming.EarlyUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), runners[3] = new PlayerLoopRunner(PlayerLoopTiming.LastEarlyUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), runners[3] = new PlayerLoopRunner(PlayerLoopTiming.LastEarlyUpdate));
// FixedUpdate // FixedUpdate
copyList[2].subSystemList = InsertRunner(copyList[2], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[4] = new ContinuationQueue(PlayerLoopTiming.FixedUpdate), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.FixedUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[4] = new ContinuationQueue(PlayerLoopTiming.FixedUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), yielders[5] = new ContinuationQueue(PlayerLoopTiming.LastFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), yielders[5] = new ContinuationQueue(PlayerLoopTiming.LastFixedUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[4] = new PlayerLoopRunner(PlayerLoopTiming.FixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[4] = new PlayerLoopRunner(PlayerLoopTiming.FixedUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), runners[5] = new PlayerLoopRunner(PlayerLoopTiming.LastFixedUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), runners[5] = new PlayerLoopRunner(PlayerLoopTiming.LastFixedUpdate));
// PreUpdate // PreUpdate
copyList[3].subSystemList = InsertRunner(copyList[3], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[6] = new ContinuationQueue(PlayerLoopTiming.PreUpdate), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PreUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[6] = new ContinuationQueue(PlayerLoopTiming.PreUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), yielders[7] = new ContinuationQueue(PlayerLoopTiming.LastPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), yielders[7] = new ContinuationQueue(PlayerLoopTiming.LastPreUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[6] = new PlayerLoopRunner(PlayerLoopTiming.PreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[6] = new PlayerLoopRunner(PlayerLoopTiming.PreUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), runners[7] = new PlayerLoopRunner(PlayerLoopTiming.LastPreUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), runners[7] = new PlayerLoopRunner(PlayerLoopTiming.LastPreUpdate));
// Update // Update
copyList[4].subSystemList = InsertRunner(copyList[4], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[8] = new ContinuationQueue(PlayerLoopTiming.Update), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[8] = new ContinuationQueue(PlayerLoopTiming.Update),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), yielders[9] = new ContinuationQueue(PlayerLoopTiming.LastUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), yielders[9] = new ContinuationQueue(PlayerLoopTiming.LastUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[8] = new PlayerLoopRunner(PlayerLoopTiming.Update), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[8] = new PlayerLoopRunner(PlayerLoopTiming.Update),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), runners[9] = new PlayerLoopRunner(PlayerLoopTiming.LastUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), runners[9] = new PlayerLoopRunner(PlayerLoopTiming.LastUpdate));
// PreLateUpdate // PreLateUpdate
copyList[5].subSystemList = InsertRunner(copyList[5], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[10] = new ContinuationQueue(PlayerLoopTiming.PreLateUpdate), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PreLateUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[10] = new ContinuationQueue(PlayerLoopTiming.PreLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), yielders[11] = new ContinuationQueue(PlayerLoopTiming.LastPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), yielders[11] = new ContinuationQueue(PlayerLoopTiming.LastPreLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[10] = new PlayerLoopRunner(PlayerLoopTiming.PreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[10] = new PlayerLoopRunner(PlayerLoopTiming.PreLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), runners[11] = new PlayerLoopRunner(PlayerLoopTiming.LastPreLateUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), runners[11] = new PlayerLoopRunner(PlayerLoopTiming.LastPreLateUpdate));
// PostLateUpdate // PostLateUpdate
copyList[6].subSystemList = InsertRunner(copyList[6], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[12] = new ContinuationQueue(PlayerLoopTiming.PostLateUpdate), i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PostLateUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[12] = new ContinuationQueue(PlayerLoopTiming.PostLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), yielders[13] = new ContinuationQueue(PlayerLoopTiming.LastPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), yielders[13] = new ContinuationQueue(PlayerLoopTiming.LastPostLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate)); typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
#if UNITY_2020_2_OR_NEWER
// TimeUpdate
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.TimeUpdate));
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), yielders[14] = new ContinuationQueue(PlayerLoopTiming.TimeUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), yielders[15] = new ContinuationQueue(PlayerLoopTiming.LastTimeUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), runners[14] = new PlayerLoopRunner(PlayerLoopTiming.TimeUpdate),
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), runners[15] = new PlayerLoopRunner(PlayerLoopTiming.LastTimeUpdate));
#endif
// Insert UniTaskSynchronizationContext to Update loop
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
copyList[i].subSystemList = InsertUniTaskSynchronizationContext(copyList[i]);
playerLoop.subSystemList = copyList; playerLoop.subSystemList = copyList;
PlayerLoop.SetPlayerLoop(playerLoop); PlayerLoop.SetPlayerLoop(playerLoop);
@@ -297,6 +390,56 @@ namespace Cysharp.Threading.Tasks
{ {
yielders[(int)timing].Enqueue(continuation); yielders[(int)timing].Enqueue(continuation);
} }
// Diagnostics helper
#if UNITY_2019_3_OR_NEWER
public static void DumpCurrentPlayerLoop()
{
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
var sb = new System.Text.StringBuilder();
sb.AppendLine($"PlayerLoop List");
foreach (var header in playerLoop.subSystemList)
{
sb.AppendFormat("------{0}------", header.type.Name);
sb.AppendLine();
foreach (var subSystem in header.subSystemList)
{
sb.AppendFormat("{0}", subSystem.type.Name);
sb.AppendLine();
if (subSystem.subSystemList != null)
{
UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
}
}
}
UnityEngine.Debug.Log(sb.ToString());
}
public static bool IsInjectedUniTaskPlayerLoop()
{
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
foreach (var header in playerLoop.subSystemList)
{
foreach (var subSystem in header.subSystemList)
{
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
{
return true;
}
}
}
return false;
}
#endif
} }
} }

View File

@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
namespace Cysharp.Threading.Tasks.Internal namespace Cysharp.Threading.Tasks
{ {
// internaly used but public, allow to user create custom operator with pooling. // internaly used but public, allow to user create custom operator with pooling.
@@ -13,6 +13,9 @@ namespace Cysharp.Threading.Tasks.Internal
{ {
internal static int MaxPoolSize; internal static int MaxPoolSize;
// avoid to use ConcurrentDictionary for safety of WebGL build.
static Dictionary<Type, Func<int>> sizes = new Dictionary<Type, Func<int>>();
static TaskPool() static TaskPool()
{ {
try try
@@ -36,12 +39,30 @@ namespace Cysharp.Threading.Tasks.Internal
{ {
MaxPoolSize = maxPoolSize; MaxPoolSize = maxPoolSize;
} }
}
public static IEnumerable<(Type, int)> GetCacheSizeInfo()
{
lock (sizes)
{
foreach (var item in sizes)
{
yield return (item.Key, item.Value());
}
}
}
public static void RegisterSizeGetter(Type type, Func<int> getSize)
{
lock (sizes)
{
sizes[type] = getSize;
}
}
}
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.
@@ -63,8 +84,9 @@ namespace Cysharp.Threading.Tasks.Internal
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);
@@ -98,22 +120,4 @@ namespace Cysharp.Threading.Tasks.Internal
return false; return false;
} }
} }
public static class TaskPoolMonitor
{
static ConcurrentDictionary<Type, Func<int>> sizes = new ConcurrentDictionary<Type, Func<int>>();
public static IEnumerable<(Type, int)> GetCacheSizeInfo()
{
foreach (var item in sizes)
{
yield return (item.Key, item.Value());
}
}
public static void RegisterSizeGetter(Type type, Func<int> getSize)
{
sizes[type] = getSize;
}
}
} }

View File

@@ -1,5 +1,4 @@
using Cysharp.Threading.Tasks.Internal; using System;
using System;
using System.Threading; using System.Threading;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
@@ -10,341 +9,302 @@ namespace Cysharp.Threading.Tasks
void OnError(Exception ex); void OnError(Exception ex);
void OnCompleted(); void OnCompleted();
void OnCanceled(CancellationToken cancellationToken); void OnCanceled(CancellationToken cancellationToken);
// set/get from TriggerEvent<T>
ITriggerHandler<T> Prev { get; set; }
ITriggerHandler<T> Next { get; set; }
} }
// be careful to use, itself is struct. // be careful to use, itself is struct.
public struct TriggerEvent<T> public struct TriggerEvent<T>
{ {
// optimize: many cases, handler is single. ITriggerHandler<T> head; // head.prev is last
ITriggerHandler<T> singleHandler; ITriggerHandler<T> iteratingHead;
ITriggerHandler<T>[] handlers; bool preserveRemoveSelf;
ITriggerHandler<T> iteratingNode;
// when running(in TrySetResult), does not add immediately(trampoline). void LogError(Exception ex)
bool isRunning; {
ITriggerHandler<T> waitHandler; #if UNITY_2018_3_OR_NEWER
MinimumQueue<ITriggerHandler<T>> waitQueue; UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
}
public void SetResult(T value) public void SetResult(T value)
{ {
isRunning = true; if (iteratingNode != null)
if (singleHandler != null)
{ {
throw new InvalidOperationException("Can not trigger itself in iterating.");
}
var h = head;
while (h != null)
{
iteratingNode = h;
try try
{ {
singleHandler.OnNext(value); h.OnNext(value);
} }
catch (Exception ex) catch (Exception ex)
{ {
#if UNITY_2018_3_OR_NEWER LogError(ex);
UnityEngine.Debug.LogException(ex); Remove(h);
#else
Console.WriteLine(ex);
#endif
} }
}
if (handlers != null) if (preserveRemoveSelf)
{
for (int i = 0; i < handlers.Length; i++)
{ {
if (handlers[i] != null) preserveRemoveSelf = false;
{ iteratingNode = null;
try var next = h.Next;
{ Remove(h);
handlers[i].OnNext(value); h = next;
}
catch (Exception ex)
{
handlers[i] = null;
#if UNITY_2018_3_OR_NEWER
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
}
}
} }
} else
isRunning = false;
if (waitHandler != null)
{
var h = waitHandler;
waitHandler = null;
Add(h);
}
if (waitQueue != null)
{
while (waitQueue.Count != 0)
{ {
Add(waitQueue.Dequeue()); h = h.Next;
} }
} }
iteratingNode = null;
if (iteratingHead != null)
{
Add(iteratingHead);
iteratingHead = null;
}
} }
public void SetCanceled(CancellationToken cancellationToken) public void SetCanceled(CancellationToken cancellationToken)
{ {
isRunning = true; if (iteratingNode != null)
if (singleHandler != null)
{ {
throw new InvalidOperationException("Can not trigger itself in iterating.");
}
var h = head;
while (h != null)
{
iteratingNode = h;
try try
{ {
(singleHandler).OnCanceled(cancellationToken); h.OnCanceled(cancellationToken);
} }
catch (Exception ex) catch (Exception ex)
{ {
#if UNITY_2018_3_OR_NEWER LogError(ex);
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
} }
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
} }
if (handlers != null) iteratingNode = null;
if (iteratingHead != null)
{ {
for (int i = 0; i < handlers.Length; i++) Add(iteratingHead);
{ iteratingHead = null;
if (handlers[i] != null)
{
try
{
(handlers[i]).OnCanceled(cancellationToken);
}
catch (Exception ex)
{
#if UNITY_2018_3_OR_NEWER
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
handlers[i] = null;
}
}
}
}
isRunning = false;
if (waitHandler != null)
{
var h = waitHandler;
waitHandler = null;
Add(h);
}
if (waitQueue != null)
{
while (waitQueue.Count != 0)
{
Add(waitQueue.Dequeue());
}
} }
} }
public void SetCompleted() public void SetCompleted()
{ {
isRunning = true; if (iteratingNode != null)
if (singleHandler != null)
{ {
throw new InvalidOperationException("Can not trigger itself in iterating.");
}
var h = head;
while (h != null)
{
iteratingNode = h;
try try
{ {
(singleHandler).OnCompleted(); h.OnCompleted();
} }
catch (Exception ex) catch (Exception ex)
{ {
#if UNITY_2018_3_OR_NEWER LogError(ex);
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
} }
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
} }
if (handlers != null) iteratingNode = null;
if (iteratingHead != null)
{ {
for (int i = 0; i < handlers.Length; i++) Add(iteratingHead);
{ iteratingHead = null;
if (handlers[i] != null)
{
try
{
(handlers[i]).OnCompleted();
}
catch (Exception ex)
{
#if UNITY_2018_3_OR_NEWER
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
handlers[i] = null;
}
}
}
}
isRunning = false;
if (waitHandler != null)
{
var h = waitHandler;
waitHandler = null;
Add(h);
}
if (waitQueue != null)
{
while (waitQueue.Count != 0)
{
Add(waitQueue.Dequeue());
}
} }
} }
public void SetError(Exception exception) public void SetError(Exception exception)
{ {
isRunning = true; if (iteratingNode != null)
if (singleHandler != null)
{ {
throw new InvalidOperationException("Can not trigger itself in iterating.");
}
var h = head;
while (h != null)
{
iteratingNode = h;
try try
{ {
singleHandler.OnError(exception); h.OnError(exception);
} }
catch (Exception ex) catch (Exception ex)
{ {
#if UNITY_2018_3_OR_NEWER LogError(ex);
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
} }
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
} }
if (handlers != null) iteratingNode = null;
if (iteratingHead != null)
{ {
for (int i = 0; i < handlers.Length; i++) Add(iteratingHead);
{ iteratingHead = null;
if (handlers[i] != null)
{
try
{
handlers[i].OnError(exception);
}
catch (Exception ex)
{
handlers[i] = null;
#if UNITY_2018_3_OR_NEWER
UnityEngine.Debug.LogException(ex);
#else
Console.WriteLine(ex);
#endif
}
}
}
}
isRunning = false;
if (waitHandler != null)
{
var h = waitHandler;
waitHandler = null;
Add(h);
}
if (waitQueue != null)
{
while (waitQueue.Count != 0)
{
Add(waitQueue.Dequeue());
}
} }
} }
public void Add(ITriggerHandler<T> handler) public void Add(ITriggerHandler<T> handler)
{ {
if (isRunning) if (handler == null) throw new ArgumentNullException(nameof(handler));
{
if (waitHandler == null)
{
waitHandler = handler;
return;
}
if (waitQueue == null) // zero node.
{ if (head == null)
waitQueue = new MinimumQueue<ITriggerHandler<T>>(4); {
} head = handler;
waitQueue.Enqueue(handler);
return; return;
} }
if (singleHandler == null) if (iteratingNode != null)
{ {
singleHandler = handler; if (iteratingHead == null)
{
iteratingHead = handler;
return;
}
var last = iteratingHead.Prev;
if (last == null)
{
// single node.
iteratingHead.Prev = handler;
iteratingHead.Next = handler;
handler.Prev = iteratingHead;
}
else
{
// multi node
iteratingHead.Prev = handler;
last.Next = handler;
handler.Prev = last;
}
} }
else else
{ {
if (handlers == null) var last = head.Prev;
if (last == null)
{ {
handlers = new ITriggerHandler<T>[4]; // single node.
head.Prev = handler;
head.Next = handler;
handler.Prev = head;
} }
else
// check empty
for (int i = 0; i < handlers.Length; i++)
{ {
if (handlers[i] == null) // multi node
{ head.Prev = handler;
handlers[i] = handler; last.Next = handler;
return; handler.Prev = last;
}
}
// full, ensure capacity
var last = handlers.Length;
{
EnsureCapacity(ref handlers);
handlers[last] = handler;
} }
} }
} }
static void EnsureCapacity(ref ITriggerHandler<T>[] array)
{
var newSize = array.Length * 2;
var newArray = new ITriggerHandler<T>[newSize];
Array.Copy(array, 0, newArray, 0, array.Length);
array = newArray;
}
public void Remove(ITriggerHandler<T> handler) public void Remove(ITriggerHandler<T> handler)
{ {
if (singleHandler == handler) if (handler == null) throw new ArgumentNullException(nameof(handler));
if (iteratingNode != null && iteratingNode == handler)
{ {
singleHandler = null; // if remove self, reserve remove self after invoke completed.
preserveRemoveSelf = true;
} }
else else
{ {
if (handlers != null) var prev = handler.Prev;
var next = handler.Next;
if (next != null)
{ {
for (int i = 0; i < handlers.Length; i++) next.Prev = prev;
}
if (handler == head)
{
head = next;
}
else if (handler == iteratingHead)
{
iteratingHead = next;
}
else
{
// when handler is head, prev indicate last so don't use it.
if (prev != null)
{ {
if (handlers[i] == handler) prev.Next = next;
}
}
if (head != null)
{
if (head.Prev == handler)
{
if (prev != head)
{ {
// fill null. head.Prev = prev;
handlers[i] = null; }
return; else
{
head.Prev = null;
} }
} }
} }
if (iteratingHead != null)
{
if (iteratingHead.Prev == handler)
{
if (prev != iteratingHead.Prev)
{
iteratingHead.Prev = prev;
}
else
{
iteratingHead.Prev = null;
}
}
}
handler.Prev = null;
handler.Next = null;
} }
} }
} }

View File

@@ -1,6 +1,5 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using Cysharp.Threading.Tasks.Linq;
using System; using System;
using System.Threading; using System.Threading;
using UnityEngine; using UnityEngine;
@@ -103,6 +102,8 @@ namespace Cysharp.Threading.Tasks.Triggers
} }
public T Current { get; private set; } public T Current { get; private set; }
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {
@@ -189,6 +190,9 @@ namespace Cysharp.Threading.Tasks.Triggers
internal CancellationToken CancellationToken => cancellationToken; internal CancellationToken CancellationToken => cancellationToken;
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce) internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)

View File

@@ -2,7 +2,9 @@
using System.Threading; using System.Threading;
using UnityEngine; using UnityEngine;
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
#endif
namespace Cysharp.Threading.Tasks.Triggers namespace Cysharp.Threading.Tasks.Triggers
{ {
@@ -715,6 +717,7 @@ namespace Cysharp.Threading.Tasks.Triggers
#endregion #endregion
#region CollisionEnter #region CollisionEnter
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnCollisionEnterHandler public interface IAsyncOnCollisionEnterHandler
{ {
@@ -771,9 +774,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionEnterHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionEnterAsync(); return ((IAsyncOnCollisionEnterHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionEnterAsync();
} }
} }
#endif
#endregion #endregion
#region CollisionEnter2D #region CollisionEnter2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnCollisionEnter2DHandler public interface IAsyncOnCollisionEnter2DHandler
{ {
@@ -830,9 +835,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionEnter2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionEnter2DAsync(); return ((IAsyncOnCollisionEnter2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionEnter2DAsync();
} }
} }
#endif
#endregion #endregion
#region CollisionExit #region CollisionExit
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnCollisionExitHandler public interface IAsyncOnCollisionExitHandler
{ {
@@ -889,9 +896,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionExitHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionExitAsync(); return ((IAsyncOnCollisionExitHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionExitAsync();
} }
} }
#endif
#endregion #endregion
#region CollisionExit2D #region CollisionExit2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnCollisionExit2DHandler public interface IAsyncOnCollisionExit2DHandler
{ {
@@ -948,9 +957,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionExit2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionExit2DAsync(); return ((IAsyncOnCollisionExit2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionExit2DAsync();
} }
} }
#endif
#endregion #endregion
#region CollisionStay #region CollisionStay
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnCollisionStayHandler public interface IAsyncOnCollisionStayHandler
{ {
@@ -1007,9 +1018,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionStayHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionStayAsync(); return ((IAsyncOnCollisionStayHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionStayAsync();
} }
} }
#endif
#endregion #endregion
#region CollisionStay2D #region CollisionStay2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnCollisionStay2DHandler public interface IAsyncOnCollisionStay2DHandler
{ {
@@ -1066,9 +1079,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCollisionStay2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionStay2DAsync(); return ((IAsyncOnCollisionStay2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionStay2DAsync();
} }
} }
#endif
#endregion #endregion
#region ControllerColliderHit #region ControllerColliderHit
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnControllerColliderHitHandler public interface IAsyncOnControllerColliderHitHandler
{ {
@@ -1125,6 +1140,7 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnControllerColliderHitHandler)new AsyncTriggerHandler<ControllerColliderHit>(this, cancellationToken, true)).OnControllerColliderHitAsync(); return ((IAsyncOnControllerColliderHitHandler)new AsyncTriggerHandler<ControllerColliderHit>(this, cancellationToken, true)).OnControllerColliderHitAsync();
} }
} }
#endif
#endregion #endregion
#region Disable #region Disable
@@ -1423,6 +1439,7 @@ namespace Cysharp.Threading.Tasks.Triggers
#endregion #endregion
#region JointBreak #region JointBreak
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnJointBreakHandler public interface IAsyncOnJointBreakHandler
{ {
@@ -1479,9 +1496,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnJointBreakHandler)new AsyncTriggerHandler<float>(this, cancellationToken, true)).OnJointBreakAsync(); return ((IAsyncOnJointBreakHandler)new AsyncTriggerHandler<float>(this, cancellationToken, true)).OnJointBreakAsync();
} }
} }
#endif
#endregion #endregion
#region JointBreak2D #region JointBreak2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnJointBreak2DHandler public interface IAsyncOnJointBreak2DHandler
{ {
@@ -1538,9 +1557,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnJointBreak2DHandler)new AsyncTriggerHandler<Joint2D>(this, cancellationToken, true)).OnJointBreak2DAsync(); return ((IAsyncOnJointBreak2DHandler)new AsyncTriggerHandler<Joint2D>(this, cancellationToken, true)).OnJointBreak2DAsync();
} }
} }
#endif
#endregion #endregion
#region MouseDown #region MouseDown
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseDownHandler public interface IAsyncOnMouseDownHandler
{ {
@@ -1597,9 +1618,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseDownHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDownAsync(); return ((IAsyncOnMouseDownHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDownAsync();
} }
} }
#endif
#endregion #endregion
#region MouseDrag #region MouseDrag
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseDragHandler public interface IAsyncOnMouseDragHandler
{ {
@@ -1656,9 +1679,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseDragHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDragAsync(); return ((IAsyncOnMouseDragHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDragAsync();
} }
} }
#endif
#endregion #endregion
#region MouseEnter #region MouseEnter
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseEnterHandler public interface IAsyncOnMouseEnterHandler
{ {
@@ -1715,9 +1740,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseEnterHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseEnterAsync(); return ((IAsyncOnMouseEnterHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseEnterAsync();
} }
} }
#endif
#endregion #endregion
#region MouseExit #region MouseExit
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseExitHandler public interface IAsyncOnMouseExitHandler
{ {
@@ -1774,9 +1801,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseExitHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseExitAsync(); return ((IAsyncOnMouseExitHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseExitAsync();
} }
} }
#endif
#endregion #endregion
#region MouseOver #region MouseOver
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseOverHandler public interface IAsyncOnMouseOverHandler
{ {
@@ -1833,9 +1862,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseOverHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseOverAsync(); return ((IAsyncOnMouseOverHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseOverAsync();
} }
} }
#endif
#endregion #endregion
#region MouseUp #region MouseUp
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseUpHandler public interface IAsyncOnMouseUpHandler
{ {
@@ -1892,9 +1923,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseUpHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsync(); return ((IAsyncOnMouseUpHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsync();
} }
} }
#endif
#endregion #endregion
#region MouseUpAsButton #region MouseUpAsButton
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
public interface IAsyncOnMouseUpAsButtonHandler public interface IAsyncOnMouseUpAsButtonHandler
{ {
@@ -1951,6 +1984,7 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMouseUpAsButtonHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsButtonAsync(); return ((IAsyncOnMouseUpAsButtonHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsButtonAsync();
} }
} }
#endif
#endregion #endregion
#region ParticleCollision #region ParticleCollision
@@ -2131,7 +2165,7 @@ namespace Cysharp.Threading.Tasks.Triggers
#endregion #endregion
#region ParticleUpdateJobScheduled #region ParticleUpdateJobScheduled
#if UNITY_2019_3_OR_NEWER #if UNITY_2019_3_OR_NEWER && (!UNITY_2019_1_OR_NEWER || UNITASK_PARTICLESYSTEM_SUPPORT)
public interface IAsyncOnParticleUpdateJobScheduledHandler public interface IAsyncOnParticleUpdateJobScheduledHandler
{ {
@@ -2782,6 +2816,7 @@ namespace Cysharp.Threading.Tasks.Triggers
#endregion #endregion
#region TriggerEnter #region TriggerEnter
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnTriggerEnterHandler public interface IAsyncOnTriggerEnterHandler
{ {
@@ -2838,9 +2873,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerEnterHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerEnterAsync(); return ((IAsyncOnTriggerEnterHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerEnterAsync();
} }
} }
#endif
#endregion #endregion
#region TriggerEnter2D #region TriggerEnter2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnTriggerEnter2DHandler public interface IAsyncOnTriggerEnter2DHandler
{ {
@@ -2897,9 +2934,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerEnter2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerEnter2DAsync(); return ((IAsyncOnTriggerEnter2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerEnter2DAsync();
} }
} }
#endif
#endregion #endregion
#region TriggerExit #region TriggerExit
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnTriggerExitHandler public interface IAsyncOnTriggerExitHandler
{ {
@@ -2956,9 +2995,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerExitHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerExitAsync(); return ((IAsyncOnTriggerExitHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerExitAsync();
} }
} }
#endif
#endregion #endregion
#region TriggerExit2D #region TriggerExit2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnTriggerExit2DHandler public interface IAsyncOnTriggerExit2DHandler
{ {
@@ -3015,9 +3056,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerExit2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerExit2DAsync(); return ((IAsyncOnTriggerExit2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerExit2DAsync();
} }
} }
#endif
#endregion #endregion
#region TriggerStay #region TriggerStay
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
public interface IAsyncOnTriggerStayHandler public interface IAsyncOnTriggerStayHandler
{ {
@@ -3074,9 +3117,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerStayHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerStayAsync(); return ((IAsyncOnTriggerStayHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerStayAsync();
} }
} }
#endif
#endregion #endregion
#region TriggerStay2D #region TriggerStay2D
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
public interface IAsyncOnTriggerStay2DHandler public interface IAsyncOnTriggerStay2DHandler
{ {
@@ -3133,6 +3178,7 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnTriggerStay2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerStay2DAsync(); return ((IAsyncOnTriggerStay2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerStay2DAsync();
} }
} }
#endif
#endregion #endregion
#region Validate #region Validate
@@ -3372,6 +3418,7 @@ namespace Cysharp.Threading.Tasks.Triggers
#endregion #endregion
#region BeginDrag #region BeginDrag
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnBeginDragHandler public interface IAsyncOnBeginDragHandler
{ {
@@ -3428,9 +3475,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnBeginDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnBeginDragAsync(); return ((IAsyncOnBeginDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnBeginDragAsync();
} }
} }
#endif
#endregion #endregion
#region Cancel #region Cancel
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnCancelHandler public interface IAsyncOnCancelHandler
{ {
@@ -3487,9 +3536,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnCancelHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnCancelAsync(); return ((IAsyncOnCancelHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnCancelAsync();
} }
} }
#endif
#endregion #endregion
#region Deselect #region Deselect
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnDeselectHandler public interface IAsyncOnDeselectHandler
{ {
@@ -3546,9 +3597,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnDeselectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnDeselectAsync(); return ((IAsyncOnDeselectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnDeselectAsync();
} }
} }
#endif
#endregion #endregion
#region Drag #region Drag
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnDragHandler public interface IAsyncOnDragHandler
{ {
@@ -3605,9 +3658,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDragAsync(); return ((IAsyncOnDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDragAsync();
} }
} }
#endif
#endregion #endregion
#region Drop #region Drop
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnDropHandler public interface IAsyncOnDropHandler
{ {
@@ -3664,9 +3719,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnDropHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDropAsync(); return ((IAsyncOnDropHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDropAsync();
} }
} }
#endif
#endregion #endregion
#region EndDrag #region EndDrag
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnEndDragHandler public interface IAsyncOnEndDragHandler
{ {
@@ -3723,9 +3780,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnEndDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnEndDragAsync(); return ((IAsyncOnEndDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnEndDragAsync();
} }
} }
#endif
#endregion #endregion
#region InitializePotentialDrag #region InitializePotentialDrag
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnInitializePotentialDragHandler public interface IAsyncOnInitializePotentialDragHandler
{ {
@@ -3782,9 +3841,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnInitializePotentialDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnInitializePotentialDragAsync(); return ((IAsyncOnInitializePotentialDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnInitializePotentialDragAsync();
} }
} }
#endif
#endregion #endregion
#region Move #region Move
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnMoveHandler public interface IAsyncOnMoveHandler
{ {
@@ -3841,9 +3902,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnMoveHandler)new AsyncTriggerHandler<AxisEventData>(this, cancellationToken, true)).OnMoveAsync(); return ((IAsyncOnMoveHandler)new AsyncTriggerHandler<AxisEventData>(this, cancellationToken, true)).OnMoveAsync();
} }
} }
#endif
#endregion #endregion
#region PointerClick #region PointerClick
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnPointerClickHandler public interface IAsyncOnPointerClickHandler
{ {
@@ -3900,9 +3963,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnPointerClickHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerClickAsync(); return ((IAsyncOnPointerClickHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerClickAsync();
} }
} }
#endif
#endregion #endregion
#region PointerDown #region PointerDown
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnPointerDownHandler public interface IAsyncOnPointerDownHandler
{ {
@@ -3959,9 +4024,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnPointerDownHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerDownAsync(); return ((IAsyncOnPointerDownHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerDownAsync();
} }
} }
#endif
#endregion #endregion
#region PointerEnter #region PointerEnter
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnPointerEnterHandler public interface IAsyncOnPointerEnterHandler
{ {
@@ -4018,9 +4085,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnPointerEnterHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerEnterAsync(); return ((IAsyncOnPointerEnterHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerEnterAsync();
} }
} }
#endif
#endregion #endregion
#region PointerExit #region PointerExit
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnPointerExitHandler public interface IAsyncOnPointerExitHandler
{ {
@@ -4077,9 +4146,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnPointerExitHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerExitAsync(); return ((IAsyncOnPointerExitHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerExitAsync();
} }
} }
#endif
#endregion #endregion
#region PointerUp #region PointerUp
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnPointerUpHandler public interface IAsyncOnPointerUpHandler
{ {
@@ -4136,9 +4207,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnPointerUpHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerUpAsync(); return ((IAsyncOnPointerUpHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerUpAsync();
} }
} }
#endif
#endregion #endregion
#region Scroll #region Scroll
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnScrollHandler public interface IAsyncOnScrollHandler
{ {
@@ -4195,9 +4268,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnScrollHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnScrollAsync(); return ((IAsyncOnScrollHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnScrollAsync();
} }
} }
#endif
#endregion #endregion
#region Select #region Select
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnSelectHandler public interface IAsyncOnSelectHandler
{ {
@@ -4254,9 +4329,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnSelectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSelectAsync(); return ((IAsyncOnSelectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSelectAsync();
} }
} }
#endif
#endregion #endregion
#region Submit #region Submit
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnSubmitHandler public interface IAsyncOnSubmitHandler
{ {
@@ -4313,9 +4390,11 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnSubmitHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSubmitAsync(); return ((IAsyncOnSubmitHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSubmitAsync();
} }
} }
#endif
#endregion #endregion
#region UpdateSelected #region UpdateSelected
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
public interface IAsyncOnUpdateSelectedHandler public interface IAsyncOnUpdateSelectedHandler
{ {
@@ -4372,6 +4451,7 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((IAsyncOnUpdateSelectedHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnUpdateSelectedAsync(); return ((IAsyncOnUpdateSelectedHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnUpdateSelectedAsync();
} }
} }
#endif
#endregion #endregion
} }

View File

@@ -25,13 +25,7 @@
("Update", "Update", "AsyncUnit", null, empty), ("Update", "Update", "AsyncUnit", null, empty),
("FixedUpdate", "FixedUpdate", "AsyncUnit", null, empty), ("FixedUpdate", "FixedUpdate", "AsyncUnit", null, empty),
("LateUpdate", "LateUpdate", "AsyncUnit", null, empty), ("LateUpdate", "LateUpdate", "AsyncUnit", null, empty),
("MouseDown", "OnMouseDown", "AsyncUnit", null, empty),
("MouseDrag", "OnMouseDrag", "AsyncUnit", null, empty),
("MouseEnter", "OnMouseEnter", "AsyncUnit", null, empty),
("MouseExit", "OnMouseExit", "AsyncUnit", null, empty),
("MouseOver", "OnMouseOver", "AsyncUnit", null, empty),
("MouseUp", "OnMouseUp", "AsyncUnit", null, empty),
("MouseUpAsButton", "OnMouseUpAsButton", "AsyncUnit", null, empty),
("ParticleCollision", "OnParticleCollision", "GameObject", null, new []{ ("GameObject", "other") }), ("ParticleCollision", "OnParticleCollision", "GameObject", null, new []{ ("GameObject", "other") }),
("RectTransformDimensionsChange", "OnRectTransformDimensionsChange", "AsyncUnit", null, empty), ("RectTransformDimensionsChange", "OnRectTransformDimensionsChange", "AsyncUnit", null, empty),
("RectTransformRemoved", "OnRectTransformRemoved", "AsyncUnit", null, empty), ("RectTransformRemoved", "OnRectTransformRemoved", "AsyncUnit", null, empty),
@@ -47,6 +41,15 @@
("BecameInvisible", "OnBecameInvisible", "AsyncUnit", null, empty), ("BecameInvisible", "OnBecameInvisible", "AsyncUnit", null, empty),
("BecameVisible", "OnBecameVisible", "AsyncUnit", null, empty), ("BecameVisible", "OnBecameVisible", "AsyncUnit", null, empty),
// Mouse... #if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
("MouseDown", "OnMouseDown", "AsyncUnit", null, empty),
("MouseDrag", "OnMouseDrag", "AsyncUnit", null, empty),
("MouseEnter", "OnMouseEnter", "AsyncUnit", null, empty),
("MouseExit", "OnMouseExit", "AsyncUnit", null, empty),
("MouseOver", "OnMouseOver", "AsyncUnit", null, empty),
("MouseUp", "OnMouseUp", "AsyncUnit", null, empty),
("MouseUpAsButton", "OnMouseUpAsButton", "AsyncUnit", null, empty),
// new in v2 // new in v2
("ApplicationFocus", "OnApplicationFocus", "bool", null, new []{("bool", "hasFocus") }), ("ApplicationFocus", "OnApplicationFocus", "bool", null, new []{("bool", "hasFocus") }),
("ApplicationPause", "OnApplicationPause", "bool", null, new []{("bool", "pauseStatus") }), ("ApplicationPause", "OnApplicationPause", "bool", null, new []{("bool", "pauseStatus") }),
@@ -103,20 +106,36 @@
Func<(string argType, string argName)[], string> BuildMethodArgument = x => string.Join(", ", x.Select(y => y.argType + " " + y.argName)); Func<(string argType, string argName)[], string> BuildMethodArgument = x => string.Join(", ", x.Select(y => y.argType + " " + y.argName));
Func<(string argType, string argName)[], string> BuildResultParameter = x => x.Length == 0 ? "AsyncUnit.Default" : "(" + string.Join(", ", x.Select(y => y.argName)) + ")"; Func<(string argType, string argName)[], string> BuildResultParameter = x => x.Length == 0 ? "AsyncUnit.Default" : "(" + string.Join(", ", x.Select(y => y.argName)) + ")";
Func<string, bool> Is2019_3 = x => x == "ParticleUpdateJobScheduled"; Func<string, bool> IsParticleSystem = x => x == "ParticleUpdateJobScheduled";
Func<string, bool> IsMouseTrigger = x => x.StartsWith("Mouse");
Func<string, string> RequirePhysicsModule = x => (x.StartsWith("Collision") || x.StartsWith("Collider") || x.StartsWith("ControllerCollider") || x.StartsWith("Joint") || x.StartsWith("Trigger"))
? (x.Contains("2D") ? "UNITASK_PHYSICS2D_SUPPORT" : "UNITASK_PHYSICS_SUPPORT")
: null;
Func<string, bool> IsUguiSystem = x => x != null;
#> #>
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System.Threading; using System.Threading;
using UnityEngine; using UnityEngine;
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
#endif
namespace Cysharp.Threading.Tasks.Triggers namespace Cysharp.Threading.Tasks.Triggers
{ {
<# foreach(var t in triggers) { #> <# foreach(var t in triggers) { #>
#region <#= t.triggerName #> #region <#= t.triggerName #>
<# if(Is2019_3(t.triggerName)) { #> <# if(IsUguiSystem(t.handlerInterface)) { #>
#if UNITY_2019_3_OR_NEWER #if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
<# } #>
<# if(IsParticleSystem(t.triggerName)) { #>
#if UNITY_2019_3_OR_NEWER && (!UNITY_2019_1_OR_NEWER || UNITASK_PARTICLESYSTEM_SUPPORT)
<# } #>
<# if(IsMouseTrigger(t.triggerName)) { #>
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
<# } #>
<# if(RequirePhysicsModule(t.triggerName) != null) { #>
#if !UNITY_2019_1_OR_NEWER || <#= RequirePhysicsModule(t.triggerName) #>
<# } #> <# } #>
public interface <#= ToInterfaceName(t.methodName) #> public interface <#= ToInterfaceName(t.methodName) #>
@@ -174,7 +193,13 @@ namespace Cysharp.Threading.Tasks.Triggers
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, true)).<#= t.methodName #>Async(); return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, true)).<#= t.methodName #>Async();
} }
} }
<# if(Is2019_3(t.triggerName)) { #> <# if(IsUguiSystem(t.handlerInterface)) { #>
#endif
<# } #>
<# if(RequirePhysicsModule(t.triggerName) != null) { #>
#endif
<# } #>
<# if(IsParticleSystem(t.triggerName) || IsMouseTrigger(t.triggerName)) { #>
#endif #endif
<# } #> <# } #>
#endregion #endregion

View File

@@ -1,13 +1,23 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using Cysharp.Threading.Tasks.Internal;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using Cysharp.Threading.Tasks.Internal;
using UnityEngine; using UnityEngine;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
{ {
public enum DelayType
{
/// <summary>use Time.deltaTime.</summary>
DeltaTime,
/// <summary>Ignore timescale, use Time.unscaledDeltaTime.</summary>
UnscaledDeltaTime,
/// <summary>use Stopwatch.GetTimestamp().</summary>
Realtime
}
public partial struct UniTask public partial struct UniTask
{ {
public static YieldAwaitable Yield(PlayerLoopTiming timing = PlayerLoopTiming.Update) public static YieldAwaitable Yield(PlayerLoopTiming timing = PlayerLoopTiming.Update)
@@ -21,6 +31,46 @@ namespace Cysharp.Threading.Tasks
return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token); return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token);
} }
/// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default)
{
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate).
/// </summary>
public static YieldAwaitable WaitForEndOfFrame()
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken)
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate).
/// </summary>
public static YieldAwaitable WaitForFixedUpdate()
{
return UniTask.Yield(PlayerLoopTiming.FixedUpdate);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken)
{
return UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken);
}
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (delayFrameCount < 0) if (delayFrameCount < 0)
@@ -34,36 +84,55 @@ namespace Cysharp.Threading.Tasks
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay); var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
if (delayTimeSpan < TimeSpan.Zero) return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
{
throw new ArgumentOutOfRangeException("Delay does not allow minus millisecondsDelay. millisecondsDelay:" + millisecondsDelay);
}
return (ignoreTimeScale)
? new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token)
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
} }
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
}
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
}
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (delayTimeSpan < TimeSpan.Zero) if (delayTimeSpan < TimeSpan.Zero)
{ {
throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan); throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan);
} }
return (ignoreTimeScale) switch (delayType)
? new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token) {
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token); case DelayType.UnscaledDeltaTime:
{
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
case DelayType.Realtime:
{
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
case DelayType.DeltaTime:
default:
{
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
}
} }
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size);
} }
CancellationToken cancellationToken; CancellationToken cancellationToken;
@@ -142,31 +211,120 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
}
~YieldPromise() sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
{
static TaskPool<NextFramePromise> pool;
NextFramePromise nextNode;
public ref NextFramePromise NextNode => ref nextNode;
static NextFramePromise()
{ {
if (TryReturn()) TaskPool.RegisterSizeGetter(typeof(NextFramePromise), () => pool.Size);
}
int frameCount;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<AsyncUnit> core;
NextFramePromise()
{
}
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{ {
GC.ReRegisterForFinalize(this); return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
} }
if (!pool.TryPop(out var result))
{
result = new NextFramePromise();
}
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
TryReturn();
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
if (frameCount == Time.frameCount)
{
return true;
}
core.TrySetResult(AsyncUnit.Default);
return false;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
return pool.TryPush(this);
} }
} }
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size);
} }
int initialFrame;
int delayFrameCount; int delayFrameCount;
CancellationToken cancellationToken; CancellationToken cancellationToken;
int currentFrameCount; int currentFrameCount;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<AsyncUnit> core;
DelayFramePromise() DelayFramePromise()
{ {
@@ -186,6 +344,7 @@ namespace Cysharp.Threading.Tasks
result.delayFrameCount = delayFrameCount; result.delayFrameCount = delayFrameCount;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -230,13 +389,27 @@ namespace Cysharp.Threading.Tasks
return false; return false;
} }
if (currentFrameCount == delayFrameCount) if (currentFrameCount == 0)
{ {
core.TrySetResult(null); if (delayFrameCount == 0) // same as Yield
{
core.TrySetResult(AsyncUnit.Default);
return false;
}
// skip in initial frame.
if (initialFrame == Time.frameCount)
{
return true;
}
}
if (++currentFrameCount >= delayFrameCount)
{
core.TrySetResult(AsyncUnit.Default);
return false; return false;
} }
currentFrameCount++;
return true; return true;
} }
@@ -249,27 +422,21 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
~DelayFramePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size);
} }
float delayFrameTimeSpan; int initialFrame;
float delayTimeSpan;
float elapsed; float elapsed;
CancellationToken cancellationToken; CancellationToken cancellationToken;
@@ -279,7 +446,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@@ -292,8 +459,9 @@ namespace Cysharp.Threading.Tasks
} }
result.elapsed = 0.0f; result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds; result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -338,8 +506,16 @@ namespace Cysharp.Threading.Tasks
return false; return false;
} }
if (elapsed == 0.0f)
{
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += Time.deltaTime; elapsed += Time.deltaTime;
if (elapsed >= delayFrameTimeSpan) if (elapsed >= delayTimeSpan)
{ {
core.TrySetResult(null); core.TrySetResult(null);
return false; return false;
@@ -352,33 +528,27 @@ namespace Cysharp.Threading.Tasks
{ {
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
delayFrameTimeSpan = default; delayTimeSpan = default;
elapsed = default; elapsed = default;
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
~DelayPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
} }
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()
{ {
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayIgnoreTimeScalePromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(DelayIgnoreTimeScalePromise), () => pool.Size);
} }
float delayFrameTimeSpan; float delayFrameTimeSpan;
float elapsed; float elapsed;
int initialFrame;
CancellationToken cancellationToken; CancellationToken cancellationToken;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@@ -401,6 +571,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f; result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds; result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -446,6 +617,14 @@ namespace Cysharp.Threading.Tasks
return false; return false;
} }
if (elapsed == 0.0f)
{
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += Time.unscaledDeltaTime; elapsed += Time.unscaledDeltaTime;
if (elapsed >= delayFrameTimeSpan) if (elapsed >= delayFrameTimeSpan)
{ {
@@ -465,13 +644,110 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this); return pool.TryPush(this);
} }
}
~DelayIgnoreTimeScalePromise() sealed class DelayRealtimePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayRealtimePromise>
{
static TaskPool<DelayRealtimePromise> pool;
DelayRealtimePromise nextNode;
public ref DelayRealtimePromise NextNode => ref nextNode;
static DelayRealtimePromise()
{ {
if (TryReturn()) TaskPool.RegisterSizeGetter(typeof(DelayRealtimePromise), () => pool.Size);
}
long delayTimeSpanTicks;
ValueStopwatch stopwatch;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<AsyncUnit> core;
DelayRealtimePromise()
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{ {
GC.ReRegisterForFinalize(this); return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
} }
if (!pool.TryPop(out var result))
{
result = new DelayRealtimePromise();
}
result.stopwatch = ValueStopwatch.StartNew();
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
TryReturn();
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
if (stopwatch.IsInvalid)
{
core.TrySetResult(AsyncUnit.Default);
return false;
}
if (stopwatch.ElapsedTicks >= delayTimeSpanTicks)
{
core.TrySetResult(AsyncUnit.Default);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stopwatch = default;
cancellationToken = default;
return pool.TryPush(this);
} }
} }
} }

View File

@@ -1,6 +1,9 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using Cysharp.Threading.Tasks.Internal;
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading; using System.Threading;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
@@ -9,10 +12,7 @@ namespace Cysharp.Threading.Tasks
{ {
static readonly UniTask CanceledUniTask = new Func<UniTask>(() => static readonly UniTask CanceledUniTask = new Func<UniTask>(() =>
{ {
var promise = new UniTaskCompletionSource(); return new UniTask(new CanceledResultSource(CancellationToken.None), 0);
promise.TrySetCanceled(CancellationToken.None);
promise.MarkHandled();
return promise.Task;
})(); })();
static class CanceledUniTaskCache<T> static class CanceledUniTaskCache<T>
@@ -21,10 +21,7 @@ namespace Cysharp.Threading.Tasks
static CanceledUniTaskCache() static CanceledUniTaskCache()
{ {
var promise = new UniTaskCompletionSource<T>(); Task = new UniTask<T>(new CanceledResultSource<T>(CancellationToken.None), 0);
promise.TrySetCanceled(CancellationToken.None);
promise.MarkHandled();
Task = promise.Task;
} }
} }
@@ -32,18 +29,22 @@ namespace Cysharp.Threading.Tasks
public static UniTask FromException(Exception ex) public static UniTask FromException(Exception ex)
{ {
var promise = new UniTaskCompletionSource(); if (ex is OperationCanceledException oce)
promise.TrySetException(ex); {
promise.MarkHandled(); return FromCanceled(oce.CancellationToken);
return promise.Task; }
return new UniTask(new ExceptionResultSource(ex), 0);
} }
public static UniTask<T> FromException<T>(Exception ex) public static UniTask<T> FromException<T>(Exception ex)
{ {
var promise = new UniTaskCompletionSource<T>(); if (ex is OperationCanceledException oce)
promise.TrySetException(ex); {
promise.MarkHandled(); return FromCanceled<T>(oce.CancellationToken);
return promise.Task; }
return new UniTask<T>(new ExceptionResultSource<T>(ex), 0);
} }
public static UniTask<T> FromResult<T>(T value) public static UniTask<T> FromResult<T>(T value)
@@ -59,10 +60,7 @@ namespace Cysharp.Threading.Tasks
} }
else else
{ {
var promise = new UniTaskCompletionSource(); return new UniTask(new CanceledResultSource(cancellationToken), 0);
promise.TrySetCanceled(cancellationToken);
promise.MarkHandled();
return promise.Task;
} }
} }
@@ -74,10 +72,7 @@ namespace Cysharp.Threading.Tasks
} }
else else
{ {
var promise = new UniTaskCompletionSource<T>(); return new UniTask<T>(new CanceledResultSource<T>(cancellationToken), 0);
promise.TrySetCanceled(cancellationToken);
promise.MarkHandled();
return promise.Task;
} }
} }
@@ -102,8 +97,7 @@ namespace Cysharp.Threading.Tasks
} }
/// <summary> /// <summary>
/// helper of create add UniTaskVoid to delegate. /// helper of fire and forget void action.
/// For example: FooEvent += () => UniTask.Void(async () => { /* */ })
/// </summary> /// </summary>
public static void Void(Func<UniTaskVoid> asyncAction) public static void Void(Func<UniTaskVoid> asyncAction)
{ {
@@ -111,7 +105,7 @@ namespace Cysharp.Threading.Tasks
} }
/// <summary> /// <summary>
/// helper of create add UniTaskVoid to delegate. /// helper of fire and forget void action.
/// </summary> /// </summary>
public static void Void(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken) public static void Void(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{ {
@@ -119,8 +113,7 @@ namespace Cysharp.Threading.Tasks
} }
/// <summary> /// <summary>
/// helper of create add UniTaskVoid to delegate. /// helper of fire and forget void action.
/// For example: FooEvent += (sender, e) => UniTask.Void(async arg => { /* */ }, (sender, e))
/// </summary> /// </summary>
public static void Void<T>(Func<T, UniTaskVoid> asyncAction, T state) public static void Void<T>(Func<T, UniTaskVoid> asyncAction, T state)
{ {
@@ -182,6 +175,153 @@ namespace Cysharp.Threading.Tasks
return new UniTask<T>(new DeferPromise<T>(factory), 0); return new UniTask<T>(new DeferPromise<T>(factory), 0);
} }
/// <summary>
/// Never complete.
/// </summary>
public static UniTask Never(CancellationToken cancellationToken)
{
return new UniTask<AsyncUnit>(new NeverPromise<AsyncUnit>(cancellationToken), 0);
}
/// <summary>
/// Never complete.
/// </summary>
public static UniTask<T> Never<T>(CancellationToken cancellationToken)
{
return new UniTask<T>(new NeverPromise<T>(cancellationToken), 0);
}
sealed class ExceptionResultSource : IUniTaskSource
{
readonly ExceptionDispatchInfo exception;
public ExceptionResultSource(Exception exception)
{
this.exception = ExceptionDispatchInfo.Capture(exception);
}
public void GetResult(short token)
{
exception.Throw();
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Faulted;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Faulted;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
{
readonly ExceptionDispatchInfo exception;
public ExceptionResultSource(Exception exception)
{
this.exception = ExceptionDispatchInfo.Capture(exception);
}
public T GetResult(short token)
{
exception.Throw();
return default;
}
void IUniTaskSource.GetResult(short token)
{
exception.Throw();
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Faulted;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Faulted;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class CanceledResultSource : IUniTaskSource
{
readonly CancellationToken cancellationToken;
public CanceledResultSource(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public void GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Canceled;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Canceled;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class CanceledResultSource<T> : IUniTaskSource<T>
{
readonly CancellationToken cancellationToken;
public CanceledResultSource(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public T GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
void IUniTaskSource.GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Canceled;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Canceled;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class DeferPromise : IUniTaskSource sealed class DeferPromise : IUniTaskSource
{ {
Func<UniTask> factory; Func<UniTask> factory;
@@ -201,10 +341,12 @@ namespace Cysharp.Threading.Tasks
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
{ {
var f = Interlocked.Exchange(ref factory, null); var f = Interlocked.Exchange(ref factory, null);
if (f == null) throw new InvalidOperationException("Can't call twice."); if (f != null)
{
task = f();
awaiter = task.GetAwaiter();
}
task = f();
awaiter = f().GetAwaiter();
return task.Status; return task.Status;
} }
@@ -243,10 +385,12 @@ namespace Cysharp.Threading.Tasks
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
{ {
var f = Interlocked.Exchange(ref factory, null); var f = Interlocked.Exchange(ref factory, null);
if (f == null) throw new InvalidOperationException("Can't call twice."); if (f != null)
{
task = f();
awaiter = task.GetAwaiter();
}
task = f();
awaiter = f().GetAwaiter();
return task.Status; return task.Status;
} }
@@ -260,6 +404,54 @@ namespace Cysharp.Threading.Tasks
return task.Status; return task.Status;
} }
} }
sealed class NeverPromise<T> : IUniTaskSource<T>
{
static readonly Action<object> cancellationCallback = CancellationCallback;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<T> core;
public NeverPromise(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
if (this.cancellationToken.CanBeCanceled)
{
this.cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
}
}
static void CancellationCallback(object state)
{
var self = (NeverPromise<T>)state;
self.core.TrySetCanceled(self.cancellationToken);
}
public T GetResult(short token)
{
return core.GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
void IUniTaskSource.GetResult(short token)
{
core.GetResult(token);
}
}
} }
internal static class CompletedTasks internal static class CompletedTasks

Some files were not shown because too many files have changed in this diff Show More