Compare commits

..

29 Commits

Author SHA1 Message Date
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
44 changed files with 3022 additions and 604 deletions

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

@@ -61,8 +61,8 @@ jobs:
# Store artifacts. # Store artifacts.
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
name: UniTask.unitypackage.zip name: UniTask.${{ env.GIT_TAG }}.unitypackage
path: ./src/UniTask/*.unitypackage path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
create-release: create-release:
needs: [build-dotnet, build-unity] needs: [build-dotnet, build-unity]

46
.gitignore vendored
View File

@@ -159,3 +159,49 @@ src/UniTask/UniTask.Tests.Editor.csproj
src/UniTask/UniTask.*.unitypackage src/UniTask/UniTask.*.unitypackage
src/UniTask/UniTask.Linq.csproj 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

View File

@@ -6,7 +6,7 @@ Provides an efficient async/await integration to Unity.
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation * Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation
* All Unity AsyncOperations and Coroutine to awaitable * All Unity AsyncOperations and Coroutine to awaitable
* PlayerLoop based task(`UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc...) that enable to replace all coroutine operation * PlayerLoop based task(`UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc..) that enable to replace all coroutine operation
* MonoBehaviour Message Events and uGUI Events as awaitable/async-enumerable * MonoBehaviour Message Events and uGUI Events as awaitable/async-enumerable
* Completely run on Unity's PlayerLoop so don't use thread and run on WebGL, wasm, etc. * Completely run on Unity's PlayerLoop so don't use thread and run on WebGL, wasm, etc.
* Asynchronous LINQ, with Channel and AsyncReactiveProperty * Asynchronous LINQ, with Channel and AsyncReactiveProperty
@@ -29,6 +29,7 @@ Provides an efficient async/await integration to Unity.
- [Awaitable Events](#awaitable-events) - [Awaitable Events](#awaitable-events)
- [Channel](#channel) - [Channel](#channel)
- [For Unit Testing](#for-unit-testing) - [For Unit Testing](#for-unit-testing)
- [Pooling Configuration](#pooling-configuration)
- [API References](#api-references) - [API References](#api-references)
- [UPM Package](#upm-package) - [UPM Package](#upm-package)
- [Install via git URL](#install-via-git-url) - [Install via git URL](#install-via-git-url)
@@ -52,21 +53,33 @@ async UniTask<string> DemoAsync()
{ {
// You can await Unity's AsyncObject // You can await Unity's AsyncObject
var asset = await Resources.LoadAsync<TextAsset>("foo"); var asset = await Resources.LoadAsync<TextAsset>("foo");
var txt = (await UnityWebRequest.Get("https://...").SendWebRequest()).downloadHandler.text;
await SceneManager.LoadSceneAsync("scene2");
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject // .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
var asset2 = await Resources.LoadAsync<TextAsset>("foo").WithCancellation(this.GetCancellationTokenOnDestroy()); var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T> // .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
await SceneManager.LoadSceneAsync("scene2").ToUniTask(Progress.Create<float>(x => Debug.Log(x))); var asset3 = await Resources.LoadAsync<TextAsset>("baz").ToUniTask(Progress.Create<float>(x => Debug.Log(x)));
// await frame-based operation like coroutine // await frame-based operation like coroutine
await UniTask.DelayFrame(100); await UniTask.DelayFrame(100);
// replacement of WaitForSeconds/WaitForSecondsRealtime // replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false); await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
// replacement of WaitForEndOfFrame(or other timing like yield return null, yield return WaitForFixedUpdate) // yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate); await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);
// replacement of yield return null
await UniTask.Yield();
await UniTask.NextFrame();
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
await UniTask.WaitForEndOfFrame();
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask.WaitForFixedUpdate();
// replacement of yield return WaitUntil // replacement of yield return WaitUntil
await UniTask.WaitUntil(() => isActive == false); await UniTask.WaitUntil(() => isActive == false);
@@ -80,9 +93,14 @@ async UniTask<string> DemoAsync()
// You can await standard task // You can await standard task
await Task.Run(() => 100); await Task.Run(() => 100);
// Multithreading, run on ThreadPool under this code(use SwitchToMainThread, same as `ObserveOnMainThreadDispatcher`) // Multithreading, run on ThreadPool under this code
await UniTask.SwitchToThreadPool(); await UniTask.SwitchToThreadPool();
/* work on ThreadPool */
// return to MainThread(same as `ObserveOnMainThread` in UniRx)
await UniTask.SwitchToMainThread();
// get async webrequest // get async webrequest
async UniTask<string> GetTextAsync(UnityWebRequest req) async UniTask<string> GetTextAsync(UnityWebRequest req)
{ {
@@ -126,6 +144,8 @@ UniTask provides three pattern of extension methods.
`WithCancellation` is a simple version of `ToUniTask`, both returns `UniTask`. Details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section. `WithCancellation` is a simple version of `ToUniTask`, both returns `UniTask`. Details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type. The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
```csharp ```csharp
@@ -320,9 +340,19 @@ public enum PlayerLoopTiming
It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop. It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop.
`PlayerLoopTiming.Update` is similar as `yield return null` in coroutine, but it is called before Update(Update is called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). If change timing to `PlayerLoopTiming.LastUpdate`, called after these Unity's update methods. `PlayerLoopTiming.Update` is similar as `yield return null` in coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine.
`PlayerLoopTiming.FixedUpdate` is similar as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine. `yield return null` and `UniTask.Yield` is similar but different. `yield return null` always return next frame but `UniTask.Yield` return next called, that is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` gurantees return next frame, this would be expected to behave exactly the same as `yield return null`.
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and faster.
AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, causes different order of Start and continuation after await. so recommend not to use `LoadSceneAsync.ToUniTask`.
In stacktrace, you can check where is running in playerloop.
![image](https://user-images.githubusercontent.com/46207/83735571-83caea80-a68b-11ea-8d22-5e22864f0d24.png)
In default, UniTask's PlayerLoop is initialized at `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`. In default, UniTask's PlayerLoop is initialized at `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`.
@@ -413,7 +443,7 @@ For debug use, enable tracking and capture stacktrace is useful but it it declin
External Assets External Assets
--- ---
In default, UniTask supports DOTween and Addressable(`AsyncOperationHandle` and `AsyncOpereationHandle<T>` as awaitable). In default, UniTask supports DOTween and Addressables(`AsyncOperationHandle` and `AsyncOpereationHandle<T>` as awaitable).
For DOTween support, require to `com.demigiant.dotween` import from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or define `UNITASK_DOTWEEN_SUPPORT` to enable it. For DOTween support, require to `com.demigiant.dotween` import from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or define `UNITASK_DOTWEEN_SUPPORT` to enable it.
@@ -649,6 +679,19 @@ public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working. UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working.
Pooling Configuration
---
UniTask is aggressively caching async promise object to achive zero allocation. In default, cache all promises but you can configure `TaskPool.SetMaxPoolSize` to your value, the value indicates cache size per type. `TaskPool.GetCacheSizeInfo` returns current cached object in pool.
```csharp
foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
{
Debug.Log(type + ":" + size);
}
```
> In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build. And also currently due to IL2CPP limitation, in IL2CPP build, UniTask do boxing AsyncStateMachine when needed so sometimes exists `one` allocation.
API References API References
--- ---
UniTask's API References is hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate). UniTask's API References is hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).
@@ -706,6 +749,16 @@ public class ZeroAllocAsyncAwaitInDotNetCore
} }
} }
} }
// UniTask does not return to original SynchronizationContext but you can use helper `ReturnToCurrentSynchronizationContext`.
public ValueTask TestAsync()
{
await using (UniTask.ReturnToCurrentSynchronizationContext())
{
await UniTask.SwitchToThreadPool();
// do anything..
}
}
``` ```
.NET Core version is intended to allow users to use UniTask as an interface when sharing code with Unity (such as [Cysharp/MagicOnion](https://github.com/Cysharp/MagicOnion/)). .NET Core version of UniTask enables smooth code sharing. .NET Core version is intended to allow users to use UniTask as an interface when sharing code with Unity (such as [Cysharp/MagicOnion](https://github.com/Cysharp/MagicOnion/)). .NET Core version of UniTask enables smooth code sharing.
@@ -714,4 +767,4 @@ Utility methods such as WhenAll which is equivalent to UniTask are provided as [
License License
--- ---
This library is under the MIT License. This library is under the MIT License.

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

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,12 +10,20 @@ 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 UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true)
@@ -26,5 +36,63 @@ namespace Cysharp.Threading.Tasks
{ {
return task.AsTask().AsUniTask(useCurrentSynchronizationContext); return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
} }
#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

@@ -1,7 +1,7 @@
<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>

View File

@@ -277,7 +277,11 @@ namespace NetCoreSandbox
#endif #endif
// await new AllocationCheck().ViaUniTaskVoid(); // await new AllocationCheck().ViaUniTaskVoid();
// AsyncTest().Forget(); // AsyncTest().Forge
Console.WriteLine("A?");
var a = await new ZeroAllocAsyncAwaitInDotNetCore().NanikaAsync(1, 2);
Console.WriteLine("RET:" + a);
await WhereSelect(); await WhereSelect();
SynchronizationContext.SetSynchronizationContext(new MySyncContext()); SynchronizationContext.SetSynchronizationContext(new MySyncContext());

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder public struct AsyncUniTaskMethodBuilder
{ {
internal IStateMachineRunnerPromise runnerPromise; IStateMachineRunnerPromise runnerPromise;
Exception ex; Exception ex;
// 1. Static Create method. // 1. Static Create method.
@@ -80,7 +80,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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);
@@ -96,7 +96,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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);
@@ -138,7 +138,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder<T> public struct AsyncUniTaskMethodBuilder<T>
{ {
internal IStateMachineRunnerPromise<T> runnerPromise; IStateMachineRunnerPromise<T> runnerPromise;
Exception ex; Exception ex;
T result; T result;
@@ -211,7 +211,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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);
@@ -227,7 +227,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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);

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)] [StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskVoidMethodBuilder public struct AsyncUniTaskVoidMethodBuilder
{ {
internal IStateMachineRunner runner; IStateMachineRunner runner;
// 1. Static Create method. // 1. Static Create method.
[DebuggerHidden] [DebuggerHidden]
@@ -70,7 +70,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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);
@@ -86,7 +86,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
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

@@ -2,6 +2,7 @@
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;
@@ -29,12 +30,26 @@ namespace Cysharp.Threading.Tasks.CompilerServices
void SetException(Exception exception); void SetException(Exception exception);
} }
internal static class StateMachineUtility
{
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 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
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine; TStateMachine stateMachine;
#endif
public Action MoveNext { get; } public Action MoveNext { get; }
@@ -43,7 +58,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
MoveNext = Run; MoveNext = Run;
} }
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,7 +66,7 @@ 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).
} }
@@ -102,7 +117,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
static TaskPool<AsyncUniTask<TStateMachine>> pool; static TaskPool<AsyncUniTask<TStateMachine>> pool;
#if ENABLE_IL2CPP
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine; TStateMachine stateMachine;
#endif
public Action MoveNext { get; } public Action MoveNext { get; }
@@ -113,7 +132,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
MoveNext = Run; MoveNext = Run;
} }
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,7 +140,7 @@ 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).
} }
@@ -213,7 +232,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{ {
static TaskPool<AsyncUniTask<TStateMachine, T>> pool; static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
#if ENABLE_IL2CPP
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine; TStateMachine stateMachine;
#endif
public Action MoveNext { get; } public Action MoveNext { get; }
@@ -224,7 +247,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
MoveNext = Run; MoveNext = Run;
} }
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,10 +255,13 @@ 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).
// UnityEngine.Debug.Log($"SetStateMachine State:" + StateMachineUtility.GetState(stateMachine));
} }
public AsyncUniTask<TStateMachine, T> NextNode { get; set; } public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
static AsyncUniTask() static AsyncUniTask()
@@ -255,6 +281,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();
} }

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)

View File

@@ -23,7 +23,7 @@ namespace Cysharp.Threading.Tasks
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken) public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
{ {
if (handle.IsDone) return UniTask.CompletedTask; if (handle.IsDone) return UniTask.CompletedTask;
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask(AsyncOperationHandleWithCancellationSource.Create(handle, 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))
@@ -77,6 +77,132 @@ namespace Cysharp.Threading.Tasks
} }
} }
sealed class AsyncOperationHandleWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource>
{
static TaskPool<AsyncOperationHandleWithCancellationSource> pool;
public AsyncOperationHandleWithCancellationSource NextNode { get; set; }
static AsyncOperationHandleWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperationHandle> continuationAction;
AsyncOperationHandle handle;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationHandleWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource Create(AsyncOperationHandle handle, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncOperationHandleWithCancellationSource();
}
result.handle = handle;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
handle.Completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperationHandle _)
{
handle.Completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
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)
{
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 (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
handle = default;
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource> sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
{ {
static TaskPool<AsyncOperationHandleConfiguredSource> pool; static TaskPool<AsyncOperationHandleConfiguredSource> pool;
@@ -210,7 +336,7 @@ namespace Cysharp.Threading.Tasks
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); if (handle.IsDone) return UniTask.FromResult(handle.Result);
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask<T>(AsyncOperationHandleWithCancellationSource<T>.Create(handle, 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))
@@ -265,6 +391,137 @@ namespace Cysharp.Threading.Tasks
} }
} }
sealed class AsyncOperationHandleWithCancellationSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource<T>>
{
static TaskPool<AsyncOperationHandleWithCancellationSource<T>> pool;
public AsyncOperationHandleWithCancellationSource<T> NextNode { get; set; }
static AsyncOperationHandleWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource<T>), () => pool.Size);
}
readonly Action<AsyncOperationHandle<T>> continuationAction;
AsyncOperationHandle<T> handle;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<T> core;
AsyncOperationHandleWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncOperationHandleWithCancellationSource<T>();
}
result.handle = handle;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
handle.Completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperationHandle<T> _)
{
handle.Completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
core.TrySetResult(handle.Result);
}
}
}
public T GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
handle = default;
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
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;

View File

@@ -93,28 +93,30 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
} }
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
static readonly TweenCallback EmptyTweenCallback = () => { }; static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onKillDelegate; readonly TweenCallback onKillDelegate;
readonly TweenCallback onUpdateDelegate;
Tween tween; Tween tween;
TweenCancelBehaviour cancelBehaviour; TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken; CancellationToken cancellationToken;
bool canceled; bool canceled;
CancellationTokenRegistration cancellationTokenRegistration; TweenCallback originalUpdateAction;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource() TweenConfiguredSource()
{ {
onKillDelegate = OnKill; onKillDelegate = OnKill;
onUpdateDelegate = OnUpdate;
} }
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
DoCancelBeforeCreate(tween, cancelBehaviour);
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
} }
@@ -127,27 +129,25 @@ namespace Cysharp.Threading.Tasks
result.cancelBehaviour = cancelBehaviour; result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3); result.originalUpdateAction = tween.onUpdate;
result.canceled = false;
result.RegisterEvent(); if (result.originalUpdateAction == result.onUpdateDelegate)
{
result.originalUpdateAction = null;
}
tween.onUpdate = result.onUpdateDelegate;
tween.onKill = result.onKillDelegate;
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version; token = result.core.Version;
return result; return result;
} }
void RegisterEvent()
{
if (cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
}
tween.OnKill(onKillDelegate);
}
void OnKill() void OnKill()
{ {
cancellationTokenRegistration.Dispose();
if (canceled) if (canceled)
{ {
core.TrySetCanceled(cancellationToken); core.TrySetCanceled(cancellationToken);
@@ -158,44 +158,84 @@ namespace Cysharp.Threading.Tasks
} }
} }
static void CancellationCallback(object state) void OnUpdate()
{ {
var self = (TweenConfiguredSource)state; originalUpdateAction?.Invoke();
switch (self.cancelBehaviour) if (!cancellationToken.IsCancellationRequested)
{
return;
}
switch (this.cancelBehaviour)
{ {
case TweenCancelBehaviour.Kill: case TweenCancelBehaviour.Kill:
default: default:
self.tween.Kill(false); this.tween.Kill(false);
break; break;
case TweenCancelBehaviour.KillAndCancelAwait: case TweenCancelBehaviour.KillAndCancelAwait:
self.canceled = true; this.canceled = true;
self.tween.Kill(false); this.tween.Kill(false);
break; break;
case TweenCancelBehaviour.KillWithCompleteCallback: case TweenCancelBehaviour.KillWithCompleteCallback:
self.tween.Kill(true); this.tween.Kill(true);
break; break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait: case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
self.canceled = true; this.canceled = true;
self.tween.Kill(true); this.tween.Kill(true);
break; break;
case TweenCancelBehaviour.Complete: case TweenCancelBehaviour.Complete:
self.tween.Complete(false); this.tween.Complete(false);
break; break;
case TweenCancelBehaviour.CompleteAndCancelAwait: case TweenCancelBehaviour.CompleteAndCancelAwait:
self.canceled = true; this.canceled = true;
self.tween.Complete(false); this.tween.Complete(false);
break; break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback: case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
self.tween.Complete(true); this.tween.Complete(true);
break; break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait: case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
self.canceled = true; this.canceled = true;
self.tween.Complete(true); this.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
this.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Canceled(instance is returned to pool.)
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; break;
case TweenCancelBehaviour.CancelAwait: 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; break;
} }
} }
@@ -212,7 +252,6 @@ namespace Cysharp.Threading.Tasks
} }
} }
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
{ {
return core.GetStatus(token); return core.GetStatus(token);
@@ -232,8 +271,11 @@ namespace Cysharp.Threading.Tasks
{ {
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
tween.onUpdate = originalUpdateAction;
tween.onKill = null;
tween = default; tween = default;
cancellationToken = default; cancellationToken = default;
originalUpdateAction = default;
return pool.TryPush(this); return pool.TryPush(this);
} }

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

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

@@ -19,6 +19,8 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken) internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
{ {
// UnityEngine.Debug.Log("Called ToArray");
var pool = ArrayPool<TSource>.Shared; var pool = ArrayPool<TSource>.Shared;
var array = pool.Rent(16); var array = pool.Rent(16);

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,6 +100,7 @@ namespace Cysharp.Threading.Tasks.Linq
if (this.period <= 0) this.period = 1; if (this.period <= 0) this.period = 1;
} }
this.initialFrame = Time.frameCount;
this.dueTimePhase = true; this.dueTimePhase = true;
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale; this.ignoreTimeScale = ignoreTimeScale;
@@ -119,9 +140,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 +168,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 +205,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,6 +219,7 @@ namespace Cysharp.Threading.Tasks.Linq
if (periodFrameCount <= 0) periodFrameCount = 1; if (periodFrameCount <= 0) periodFrameCount = 1;
} }
this.initialFrame = Time.frameCount;
this.dueTimePhase = true; this.dueTimePhase = true;
this.dueTimeFrameCount = dueTimeFrameCount; this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount; this.periodFrameCount = periodFrameCount;
@@ -228,11 +263,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

@@ -92,8 +92,10 @@ 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;
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;
@@ -177,6 +179,11 @@ namespace Cysharp.Threading.Tasks
// 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;

View File

@@ -3,7 +3,6 @@
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
@@ -21,6 +20,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)
@@ -152,27 +191,25 @@ namespace Cysharp.Threading.Tasks
} }
} }
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise> sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
{ {
static TaskPool<DelayFramePromise> pool; static TaskPool<NextFramePromise> pool;
public DelayFramePromise NextNode { get; set; } public NextFramePromise NextNode { get; set; }
static DelayFramePromise() static NextFramePromise()
{ {
TaskPool.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(NextFramePromise), () => pool.Size);
} }
int delayFrameCount; int frameCount;
CancellationToken cancellationToken; CancellationToken cancellationToken;
UniTaskCompletionSourceCore<AsyncUnit> core;
int currentFrameCount; NextFramePromise()
UniTaskCompletionSourceCore<object> core;
DelayFramePromise()
{ {
} }
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@@ -181,10 +218,10 @@ namespace Cysharp.Threading.Tasks
if (!pool.TryPop(out var result)) if (!pool.TryPop(out var result))
{ {
result = new DelayFramePromise(); result = new NextFramePromise();
} }
result.delayFrameCount = delayFrameCount; result.frameCount = Time.frameCount;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -230,13 +267,133 @@ namespace Cysharp.Threading.Tasks
return false; return false;
} }
if (currentFrameCount == delayFrameCount) if (frameCount == Time.frameCount)
{ {
core.TrySetResult(null); return true;
}
core.TrySetResult(AsyncUnit.Default);
return false;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
return pool.TryPush(this);
}
~NextFramePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
{
static TaskPool<DelayFramePromise> pool;
public DelayFramePromise NextNode { get; set; }
static DelayFramePromise()
{
TaskPool.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size);
}
int initialFrame;
int delayFrameCount;
CancellationToken cancellationToken;
int currentFrameCount;
UniTaskCompletionSourceCore<AsyncUnit> core;
DelayFramePromise()
{
}
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new DelayFramePromise();
}
result.delayFrameCount = delayFrameCount;
result.cancellationToken = cancellationToken;
result.initialFrame = Time.frameCount;
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 (currentFrameCount == 0)
{
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;
} }
@@ -269,6 +426,7 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size);
} }
int initialFrame;
float delayFrameTimeSpan; float delayFrameTimeSpan;
float elapsed; float elapsed;
CancellationToken cancellationToken; CancellationToken cancellationToken;
@@ -294,6 +452,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f; result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds; result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.initialFrame = Time.frameCount;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -338,6 +497,14 @@ 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 >= delayFrameTimeSpan)
{ {
@@ -379,6 +546,7 @@ namespace Cysharp.Threading.Tasks
float delayFrameTimeSpan; float delayFrameTimeSpan;
float elapsed; float elapsed;
int initialFrame;
CancellationToken cancellationToken; CancellationToken cancellationToken;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@@ -401,6 +569,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 = Time.frameCount;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@@ -446,6 +615,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)
{ {

View File

@@ -204,7 +204,7 @@ namespace Cysharp.Threading.Tasks
if (f == null) throw new InvalidOperationException("Can't call twice."); if (f == null) throw new InvalidOperationException("Can't call twice.");
task = f(); task = f();
awaiter = f().GetAwaiter(); awaiter = task.GetAwaiter();
return task.Status; return task.Status;
} }
@@ -246,7 +246,7 @@ namespace Cysharp.Threading.Tasks
if (f == null) throw new InvalidOperationException("Can't call twice."); if (f == null) throw new InvalidOperationException("Can't call twice.");
task = f(); task = f();
awaiter = f().GetAwaiter(); awaiter = task.GetAwaiter();
return task.Status; return task.Status;
} }

View File

@@ -351,6 +351,8 @@ namespace Cysharp.Threading.Tasks
{ {
get get
{ {
if (!dontPostWhenSameContext) return false;
var current = SynchronizationContext.Current; var current = SynchronizationContext.Current;
if (current == synchronizationContext) if (current == synchronizationContext)
{ {

View File

@@ -78,7 +78,11 @@ namespace Cysharp.Threading.Tasks
return default; return default;
} }
#if NETSTANDARD2_0
return self.AsValueTask();
#else
return new System.Threading.Tasks.ValueTask(self.source, self.token); return new System.Threading.Tasks.ValueTask(self.source, self.token);
#endif
} }
#endif #endif
@@ -439,7 +443,11 @@ namespace Cysharp.Threading.Tasks
return new System.Threading.Tasks.ValueTask<T>(self.result); return new System.Threading.Tasks.ValueTask<T>(self.result);
} }
#if NETSTANDARD2_0
return self.AsValueTask();
#else
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token); return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
#endif
} }
#endif #endif

View File

@@ -621,9 +621,8 @@ namespace Cysharp.Threading.Tasks
if (exception != null) if (exception != null)
{ {
// throw exception on iterator (main)thread. exception.Throw();
// unfortunately unity test-runner can not handle throw exception on hand-write IEnumerator.MoveNext. return false;
UnityEngine.Debug.LogException(exception.SourceException);
} }
return !completed; return !completed;
@@ -692,9 +691,8 @@ namespace Cysharp.Threading.Tasks
if (exception != null) if (exception != null)
{ {
// throw exception on iterator (main)thread. exception.Throw();
// unfortunately unity test-runner can not handle throw exception on hand-write IEnumerator.MoveNext. return false;
UnityEngine.Debug.LogException(exception.SourceException);
} }
return !completed; return !completed;

View File

@@ -25,7 +25,7 @@ namespace Cysharp.Threading.Tasks
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.CompletedTask; if (asyncOperation.isDone) return UniTask.CompletedTask;
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask(AsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
@@ -75,7 +75,127 @@ namespace Cysharp.Threading.Tasks
} }
} }
class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource> sealed class AsyncOperationWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationWithCancellationSource>
{
static TaskPool<AsyncOperationWithCancellationSource> pool;
public AsyncOperationWithCancellationSource NextNode { get; set; }
static AsyncOperationWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncOperationWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
AsyncOperation asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource Create(AsyncOperation asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncOperationWithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(AsyncUnit.Default);
}
}
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
{ {
static TaskPool<AsyncOperationConfiguredSource> pool; static TaskPool<AsyncOperationConfiguredSource> pool;
public AsyncOperationConfiguredSource NextNode { get; set; } public AsyncOperationConfiguredSource NextNode { get; set; }
@@ -124,7 +244,6 @@ namespace Cysharp.Threading.Tasks
{ {
try try
{ {
core.GetResult(token); core.GetResult(token);
} }
finally finally
@@ -133,6 +252,7 @@ namespace Cysharp.Threading.Tasks
} }
} }
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
{ {
return core.GetStatus(token); return core.GetStatus(token);
@@ -203,7 +323,7 @@ namespace Cysharp.Threading.Tasks
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset); if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask<UnityEngine.Object>(ResourceRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
@@ -257,7 +377,131 @@ namespace Cysharp.Threading.Tasks
} }
} }
class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource> sealed class ResourceRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestWithCancellationSource>
{
static TaskPool<ResourceRequestWithCancellationSource> pool;
public ResourceRequestWithCancellationSource NextNode { get; set; }
static ResourceRequestWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(ResourceRequestWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
ResourceRequest asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
ResourceRequestWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new ResourceRequestWithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(asyncOperation.asset);
}
}
public UnityEngine.Object GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~ResourceRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
{ {
static TaskPool<ResourceRequestConfiguredSource> pool; static TaskPool<ResourceRequestConfiguredSource> pool;
public ResourceRequestConfiguredSource NextNode { get; set; } public ResourceRequestConfiguredSource NextNode { get; set; }
@@ -306,7 +550,6 @@ namespace Cysharp.Threading.Tasks
{ {
try try
{ {
return core.GetResult(token); return core.GetResult(token);
} }
finally finally
@@ -390,7 +633,7 @@ namespace Cysharp.Threading.Tasks
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset); if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask<UnityEngine.Object>(AssetBundleRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
@@ -444,7 +687,131 @@ namespace Cysharp.Threading.Tasks
} }
} }
class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource> sealed class AssetBundleRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestWithCancellationSource>
{
static TaskPool<AssetBundleRequestWithCancellationSource> pool;
public AssetBundleRequestWithCancellationSource NextNode { get; set; }
static AssetBundleRequestWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
AssetBundleRequest asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
AssetBundleRequestWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AssetBundleRequestWithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(asyncOperation.asset);
}
}
public UnityEngine.Object GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
{ {
static TaskPool<AssetBundleRequestConfiguredSource> pool; static TaskPool<AssetBundleRequestConfiguredSource> pool;
public AssetBundleRequestConfiguredSource NextNode { get; set; } public AssetBundleRequestConfiguredSource NextNode { get; set; }
@@ -545,11 +912,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn() bool TryReturn()
{ {
TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this); return pool.TryPush(this);
} }
@@ -576,7 +943,7 @@ namespace Cysharp.Threading.Tasks
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle); if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask<AssetBundle>(AssetBundleCreateRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
@@ -630,7 +997,131 @@ namespace Cysharp.Threading.Tasks
} }
} }
class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource> sealed class AssetBundleCreateRequestWithCancellationSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestWithCancellationSource>
{
static TaskPool<AssetBundleCreateRequestWithCancellationSource> pool;
public AssetBundleCreateRequestWithCancellationSource NextNode { get; set; }
static AssetBundleCreateRequestWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(AssetBundleCreateRequestWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
AssetBundleCreateRequest asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<AssetBundle> core;
AssetBundleCreateRequestWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AssetBundleCreateRequestWithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(asyncOperation.assetBundle);
}
}
public AssetBundle GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleCreateRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
{ {
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool; static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; } public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
@@ -731,11 +1222,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn() bool TryReturn()
{ {
TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this); return pool.TryPush(this);
} }
@@ -763,7 +1254,7 @@ namespace Cysharp.Threading.Tasks
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest); if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest);
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, out var token), token); return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
@@ -817,7 +1308,132 @@ namespace Cysharp.Threading.Tasks
} }
} }
class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource> sealed class UnityWebRequestAsyncOperationWithCancellationSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationWithCancellationSource>
{
static TaskPool<UnityWebRequestAsyncOperationWithCancellationSource> pool;
public UnityWebRequestAsyncOperationWithCancellationSource NextNode { get; set; }
static UnityWebRequestAsyncOperationWithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationWithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
UnityWebRequestAsyncOperation asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<UnityWebRequest> core;
UnityWebRequestAsyncOperationWithCancellationSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new UnityWebRequestAsyncOperationWithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(asyncOperation.webRequest);
}
}
public UnityWebRequest GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
asyncOperation.webRequest.Abort();
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~UnityWebRequestAsyncOperationWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
{ {
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool; static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; } public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
@@ -866,7 +1482,6 @@ namespace Cysharp.Threading.Tasks
{ {
try try
{ {
return core.GetResult(token); return core.GetResult(token);
} }
finally finally
@@ -920,11 +1535,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn() bool TryReturn()
{ {
TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this); return pool.TryPush(this);
} }

View File

@@ -37,7 +37,7 @@ namespace Cysharp.Threading.Tasks
<# if(t.returnType == "UnityWebRequest") { #> <# if(t.returnType == "UnityWebRequest") { #>
#if ENABLE_UNITYWEBREQUEST #if ENABLE_UNITYWEBREQUEST
<# } #> <# } #>
#region <#= t.typeName #> #region <#= t.typeName #>
public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation) public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation)
{ {
@@ -45,18 +45,18 @@ namespace Cysharp.Threading.Tasks
return new <#= t.typeName #>Awaiter(asyncOperation); return new <#= t.typeName #>Awaiter(asyncOperation);
} }
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation) public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>WithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
} }
public static <#= ToUniTaskReturnType(t.returnType) #> ConfigureAwait(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
} }
public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion
@@ -106,14 +106,153 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }
class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, IPromisePoolItem sealed class <#= t.typeName #>WithCancellationSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>WithCancellationSource>
{ {
static readonly PromisePool<<#= t.typeName #>ConfiguredSource> pool = new PromisePool<<#= t.typeName #>ConfiguredSource>(); static TaskPool<<#= t.typeName #>WithCancellationSource> pool;
public <#= t.typeName #>WithCancellationSource NextNode { get; set; }
static <#= t.typeName #>WithCancellationSource()
{
TaskPool.RegisterSizeGetter(typeof(<#= t.typeName #>WithCancellationSource), () => pool.Size);
}
readonly Action<AsyncOperation> continuationAction;
<#= t.typeName #> asyncOperation;
CancellationToken cancellationToken;
bool completed;
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
<#= t.typeName #>WithCancellationSource()
{
continuationAction = Continuation;
}
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<#= IsVoid(t) ? "" : $"<{t.returnType}>" #>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new <#= t.typeName #>WithCancellationSource();
}
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.completed = false;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
asyncOperation.completed += result.continuationAction;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperation _)
{
asyncOperation.completed -= continuationAction;
if (completed)
{
TryReturn();
}
else
{
completed = true;
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
}
}
public <#= t.returnType #> GetResult(short token)
{
<# if (!IsVoid(t)) { #>
return core.GetResult(token);
<# } else { #>
core.GetResult(token);
<# } #>
}
<# if (!IsVoid(t)) { #>
void IUniTaskSource.GetResult(short token)
{
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 bool MoveNext()
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
<# if(t.returnType == "UnityWebRequest") { #>
asyncOperation.webRequest.Abort();
<# } #>
core.TrySetCanceled(cancellationToken);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
cancellationToken = default;
return pool.TryPush(this);
}
~<#= t.typeName #>WithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
{
static TaskPool<<#= t.typeName #>ConfiguredSource> pool;
public <#= t.typeName #>ConfiguredSource NextNode { get; set; }
static <#= t.typeName #>ConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(<#= t.typeName #>ConfiguredSource), () => pool.Size);
}
<#= t.typeName #> asyncOperation; <#= t.typeName #> asyncOperation;
IProgress<float> progress; IProgress<float> progress;
@@ -133,7 +272,10 @@ namespace Cysharp.Threading.Tasks
return AutoResetUniTaskCompletionSource<#= IsVoid(t) ? "" : $"<{t.returnType}>" #>.CreateFromCanceled(cancellationToken, out token); return AutoResetUniTaskCompletionSource<#= IsVoid(t) ? "" : $"<{t.returnType}>" #>.CreateFromCanceled(cancellationToken, out token);
} }
var result = pool.TryRent() ?? new <#= t.typeName #>ConfiguredSource(); if (!pool.TryPop(out var result))
{
result = new <#= t.typeName #>ConfiguredSource();
}
result.asyncOperation = asyncOperation; result.asyncOperation = asyncOperation;
result.progress = progress; result.progress = progress;
@@ -151,8 +293,6 @@ namespace Cysharp.Threading.Tasks
{ {
try try
{ {
TaskTracker.RemoveTracking(this);
<# if (!IsVoid(t)) { #> <# if (!IsVoid(t)) { #>
return core.GetResult(token); return core.GetResult(token);
<# } else { #> <# } else { #>
@@ -161,7 +301,7 @@ namespace Cysharp.Threading.Tasks
} }
finally finally
{ {
pool.TryReturn(this); TryReturn();
} }
} }
@@ -191,6 +331,9 @@ namespace Cysharp.Threading.Tasks
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
<# if(t.returnType == "UnityWebRequest") { #>
asyncOperation.webRequest.Abort();
<# } #>
core.TrySetCanceled(cancellationToken); core.TrySetCanceled(cancellationToken);
return false; return false;
} }
@@ -209,24 +352,26 @@ namespace Cysharp.Threading.Tasks
return true; return true;
} }
public void Reset() bool TryReturn()
{ {
TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
return pool.TryPush(this);
} }
~<#= t.typeName #>ConfiguredSource() ~<#= t.typeName #>ConfiguredSource()
{ {
if (pool.TryReturn(this)) if (TryReturn())
{ {
GC.ReRegisterForFinalize(this); GC.ReRegisterForFinalize(this);
} }
} }
} }
# endregion #endregion
<# if(t.returnType == "UnityWebRequest") { #> <# if(t.returnType == "UnityWebRequest") { #>
#endif #endif
<# } #> <# } #>

View File

@@ -1,7 +1,7 @@
{ {
"name": "com.cysharp.unitask", "name": "com.cysharp.unitask",
"displayName": "UniTask", "displayName": "UniTask",
"version": "2.0.13", "version": "2.0.15",
"unity": "2018.4", "unity": "2018.4",
"description": "Provides an efficient async/await integration to Unity.", "description": "Provides an efficient async/await integration to Unity.",
"keywords": [ "async/await", "async", "Task", "UniTask" ], "keywords": [ "async/await", "async", "Task", "UniTask" ],

View File

@@ -21,13 +21,15 @@ public class ExceptionExamples : MonoBehaviour
private void Start() private void Start()
{ {
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; UnityEngine.Debug.Log("ExceptionScene, LoopType:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
ThrowFromAsyncVoid(); //TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
_ = ThrowFromTask();
_ = ThrowFromUniTask();
ThrowFromNonAsync(); //ThrowFromAsyncVoid();
//_ = ThrowFromTask();
//_ = ThrowFromUniTask();
//ThrowFromNonAsync();
} }
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)

View File

@@ -14,6 +14,8 @@ using UnityEngine;
using UnityEngine.LowLevel; using UnityEngine.LowLevel;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine.UI; using UnityEngine.UI;
using UnityEngine.SceneManagement;
// using DG.Tweening; // using DG.Tweening;
@@ -264,11 +266,14 @@ public class SandboxMain : MonoBehaviour
//var r = UniAsync("https://bing.com/", cts.Token); //var r = UniAsync("https://bing.com/", cts.Token);
//cts.Cancel(); //cts.Cancel();
//await r; //await r;
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest(); Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType);
Debug.Log("UNIASYNC1 ");
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
Debug.Log("UNIASYNC2"); // var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
// foo.downloadHandler.text;
//
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().WithCancellation(CancellationToken.None);
Debug.Log("SendWebRequestWithCancellationDone:" + PlayerLoopInfo.CurrentLoopType);
} }
catch catch
{ {
@@ -301,10 +306,210 @@ public class SandboxMain : MonoBehaviour
return 10; return 10;
} }
async UniTask<int> Ex()
async UniTaskVoid Start()
{ {
await UniTask.SwitchToMainThread(); await UniTask.Yield();
//throw new Exception();
await UniTask.Delay(TimeSpan.FromSeconds(15));
return 0;
}
IEnumerator CoroutineRun()
{
UnityEngine.Debug.Log("Before Coroutine yield return null," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
yield return null;
UnityEngine.Debug.Log("After Coroutine yield return null," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
IEnumerator CoroutineRun2()
{
UnityEngine.Debug.Log("Before Coroutine yield return WaitForEndOfFrame," + Time.frameCount);
yield return new WaitForEndOfFrame();
UnityEngine.Debug.Log("After Coroutine yield return WaitForEndOfFrame," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
yield return new WaitForEndOfFrame();
UnityEngine.Debug.Log("Onemore After Coroutine yield return WaitForEndOfFrame," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
async UniTaskVoid AsyncRun()
{
UnityEngine.Debug.Log("Before async Yield(default)," + Time.frameCount);
await UniTask.Yield();
UnityEngine.Debug.Log("After async Yield(default)," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
async UniTaskVoid AsyncLastUpdate()
{
UnityEngine.Debug.Log("Before async Yield(LastUpdate)," + Time.frameCount);
await UniTask.Yield(PlayerLoopTiming.LastUpdate);
UnityEngine.Debug.Log("After async Yield(LastUpdate)," + Time.frameCount);
}
async UniTaskVoid AsyncLastLast()
{
UnityEngine.Debug.Log("Before async Yield(LastPostLateUpdate)," + Time.frameCount);
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
UnityEngine.Debug.Log("After async Yield(LastPostLateUpdate)," + Time.frameCount);
}
async UniTaskVoid Yieldding()
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
StartCoroutine(CoroutineRun());
}
async UniTaskVoid AsyncFixedUpdate()
{
while (true)
{
await UniTask.WaitForFixedUpdate();
Debug.Log("Async:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
}
IEnumerator CoroutineFixedUpdate()
{
while (true)
{
yield return new WaitForFixedUpdate();
Debug.Log("Coroutine:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
}
private void FixedUpdate()
{
// Debug.Log("FixedUpdate:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
}
async UniTaskVoid DelayFrame3_Pre()
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
Debug.Log("Before framecount:" + Time.frameCount);
await UniTask.DelayFrame(3);
Debug.Log("After framecount:" + Time.frameCount);
}
async UniTaskVoid DelayFrame3_Post()
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
Debug.Log("Before framecount:" + Time.frameCount);
await UniTask.DelayFrame(3);
Debug.Log("After framecount:" + Time.frameCount);
}
async UniTask TestCoroutine()
{
await UniTask.Yield();
throw new Exception("foobarbaz");
}
async UniTask DelayCheck()
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
Debug.Log("before");
var t = UniTask.Delay(TimeSpan.FromSeconds(1), ignoreTimeScale: false);
await t;
Debug.Log("after");
}
private async UniTaskVoid ExecuteAsync()
{
Debug.Log("1");
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
}
Debug.Log("------------------");
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
Debug.Log("2");
}
}
void Start()
{
PlayerLoopInfo.Inject();
//_ = AsyncFixedUpdate();
//StartCoroutine(CoroutineFixedUpdate());
//StartCoroutine(TestCoroutine().ToCoroutine());
// Application.logMessageReceived += Application_logMessageReceived;
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
_ = ExecuteAsync();
await UniTask.Yield();
//await DelayCheck();
/*
UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
StartCoroutine(CoroutineRun());
StartCoroutine(CoroutineRun2());
_ = AsyncRun();
_ = AsyncLastUpdate();
_ = AsyncLastLast();
*/
//await UniTask.Yield();
//_ = Test2();
// EarlyUpdate.ExecuteMainThreadJobs
// _ = Test2();
//var t = await Resources.LoadAsync<TextAsset>(Application.streamingAssetsPath + "test.txt");
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + (t != null));
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + ((TextAsset)t).text);
//await UniTask.Yield(PlayerLoopTiming.LastUpdate);
//UnityEngine.Debug.Log("after update:" + Time.frameCount);
////await UniTask.NextFrame();
////await UniTask.Yield();
////UnityEngine.Debug.Log("after update nextframe:" + Time.frameCount);
//StartCoroutine(CoroutineRun2());
////StartCoroutine(CoroutineRun());
//UnityEngine.Debug.Log("FOO?");
//_ = DelayFrame3_Pre();
//await UniTask.Yield();
}));
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
_ = DelayFrame3_Post();
await UniTask.Yield();
//await UniTask.Yield(PlayerLoopTiming.LastPreUpdate);
//UnityEngine.Debug.Log("before update:" + Time.frameCount);
//await UniTask.NextFrame();
//await UniTask.Yield();
//UnityEngine.Debug.Log("before update nextframe:" + Time.frameCount);
//StartCoroutine(CoroutineRun());
//UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
//_ = Yieldding();
//var cts = new CancellationTokenSource();
//UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
//var la = SceneManager.LoadSceneAsync("Scenes/ExceptionExamples").WithCancellation(cts.Token);
////cts.Cancel();
//await la;
//UnityEngine.Debug.Log("End LoadSceneAsync" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
}));
//return;
//await UniTask.SwitchToMainThread();
//UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty) //UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty)
// .Do(_ => { }, () => Debug.Log("COMPLETED")) // .Do(_ => { }, () => Debug.Log("COMPLETED"))
@@ -315,10 +520,29 @@ public class SandboxMain : MonoBehaviour
// .Forget(); // .Forget();
//_ = Test1(); //_ = Test1();
Test2().Forget(); //Test2().Forget();
//StartCoroutine(Test3("https://bing.com/")); //StartCoroutine(Test3("https://bing.com/"));
//bool flip = false;
//var rect = cancelButton.GetComponent<RectTransform>();
//var cts = new CancellationTokenSource();
//var ct = cts.Token;
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
//{
// await rect.DOMoveX(10f * (flip ? -1 : 1), 3).OnUpdate(() => { Debug.Log("UPDATE YEAH"); }).WithCancellation(ct);
// flip = !flip;
// // ok.
//}));
//cancelButton.onClick.AddListener(() =>
//{
// cts.Cancel();
//});
// DG.Tweening.Core.TweenerCore<int> // DG.Tweening.Core.TweenerCore<int>
//Debug.Log("GO MOVEX"); //Debug.Log("GO MOVEX");
//await okButton.GetComponent<RectTransform>().DOMoveX(-10.2f, 3).WithCancellation(CancellationToken.None); //await okButton.GetComponent<RectTransform>().DOMoveX(-10.2f, 3).WithCancellation(CancellationToken.None);
@@ -329,7 +553,7 @@ public class SandboxMain : MonoBehaviour
//await okButton.GetComponent<RectTransform>().DOMoveY(10.2f, 3).WithCancellation(CancellationToken.None); //await okButton.GetComponent<RectTransform>().DOMoveY(10.2f, 3).WithCancellation(CancellationToken.None);
//Debug.Log("AGAIN END MOVE"); //Debug.Log("AGAIN END MOVE");
Debug.Log(Test().GetType().FullName); //Debug.Log(Test().GetType().FullName);
@@ -383,11 +607,10 @@ public class SandboxMain : MonoBehaviour
//{ //{
okButton.onClick.AddListener(UniTask.UnityAction(async () => //foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
{ //{
await UniTask.Yield(); // Debug.Log(type + ":" + size);
Debug.Log("Yeha"); //}
}));
//}).Forget(); //}).Forget();
@@ -396,7 +619,7 @@ public class SandboxMain : MonoBehaviour
//okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield())); //okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
PlayerLoopInfo.Inject();
//UpdateUniTask().Forget(); //UpdateUniTask().Forget();
@@ -405,15 +628,21 @@ public class SandboxMain : MonoBehaviour
//await UniTask.Delay(TimeSpan.FromSeconds(1)); //await UniTask.Delay(TimeSpan.FromSeconds(1));
_ = ReturnToMainThreadTest(); // _ = ReturnToMainThreadTest();
//GameObject.Destroy(this.gameObject); //GameObject.Destroy(this.gameObject);
SynchronizationContext.Current.Post(_ => }
{
//UnityEngine.Debug.Log("Post:" + PlayerLoopInfo.CurrentLoopType); private void Application_logMessageReceived2(string condition, string stackTrace, LogType type)
}, null); {
throw new NotImplementedException();
}
private void Application_logMessageReceived1(string condition, string stackTrace, LogType type)
{
throw new NotImplementedException();
} }
async UniTaskVoid UpdateUniTask() async UniTaskVoid UpdateUniTask()

View File

@@ -126,15 +126,15 @@ namespace Cysharp.Threading.TasksTests
await ToaruCoroutineEnumerator(); // wait 5 frame:) await ToaruCoroutineEnumerator(); // wait 5 frame:)
}); });
[UnityTest] //[UnityTest]
public IEnumerator JobSystem() => UniTask.ToCoroutine(async () => //public IEnumerator JobSystem() => UniTask.ToCoroutine(async () =>
{ //{
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) }; // var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
JobHandle.ScheduleBatchedJobs(); // JobHandle.ScheduleBatchedJobs();
await job.Schedule(); // await job.Schedule();
job.inOut[0].Should().Be(999); // job.inOut[0].Should().Be(999);
job.inOut.Dispose(); // job.inOut.Dispose();
}); //});
class MyMyClass class MyMyClass
{ {
@@ -197,7 +197,7 @@ namespace Cysharp.Threading.TasksTests
//await UniTask.SwitchToThreadPool(); //await UniTask.SwitchToThreadPool();
@@ -269,7 +269,8 @@ namespace Cysharp.Threading.TasksTests
var first = Time.frameCount; var first = Time.frameCount;
var canceled = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow(); var canceled = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow();
(Time.frameCount - first).Should().Be(11); // 10 frame canceled var r = (Time.frameCount - first);
(9 < r && r < 11).Should().BeTrue();
canceled.Should().Be(true); canceled.Should().Be(true);
}); });
@@ -369,6 +370,24 @@ namespace Cysharp.Threading.TasksTests
throw new Exception("MyException"); throw new Exception("MyException");
} }
[UnityTest]
public IEnumerator NextFrame1() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.LastUpdate);
var frame = Time.frameCount;
await UniTask.NextFrame();
Time.frameCount.Should().Be(frame + 1);
});
[UnityTest]
public IEnumerator NextFrame2() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var frame = Time.frameCount;
await UniTask.NextFrame();
Time.frameCount.Should().Be(frame + 1);
});
[UnityTest] [UnityTest]
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () => public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
{ {

View File

@@ -0,0 +1,97 @@
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using NUnit.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.TestTools;
namespace Cysharp.Threading.TasksTests
{
public class Cachelike
{
[UnityTest]
public IEnumerator Check() => UniTask.ToCoroutine(async () =>
{
{
var v = await CachedCheck("foo", 10);
v.Should().Be(10);
var v2 = await CachedCheck("bar", 20);
v2.Should().Be(20);
var v3 = await CachedCheck("baz", 30);
v3.Should().Be(30);
}
{
var v = await CachedCheck("foo", 10);
v.Should().Be(10);
var v2 = await CachedCheck("bar", 20);
v2.Should().Be(20);
var v3 = await CachedCheck("baz", 30);
v3.Should().Be(30);
}
{
var v = CachedCheck("foo", 10);
var v2 = CachedCheck("bar", 20);
var v3 = CachedCheck("baz", 30);
(await v).Should().Be(10);
(await v2).Should().Be(20);
(await v3).Should().Be(30);
}
{
var v = CachedCheck("foo", 10, true);
var v2 = CachedCheck("bar", 20, true);
var v3 = CachedCheck("baz", 30, true);
(await v).Should().Be(10);
(await v2).Should().Be(20);
(await v3).Should().Be(30);
}
});
static Dictionary<string, int> cacheDict = new Dictionary<string, int>();
async UniTask<int> CachedCheck(string cache, int value, bool yield = false)
{
if (!cacheDict.ContainsKey(cache))
{
await UniTask.Yield();
}
if (yield)
{
await UniTask.Yield();
}
if (cacheDict.TryGetValue(cache, out var v))
{
return v;
}
cacheDict.Add(cache, value);
return value;
}
}
}

View File

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

View File

@@ -0,0 +1,394 @@
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using NUnit.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.TestTools;
namespace Cysharp.Threading.TasksTests
{
public class DelayTest
{
//[UnityTest]
//public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
//{
// for (int i = 1; i < 5; i++)
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(i);
// Time.frameCount.Should().Be(frameCount + i);
// }
// for (int i = 1; i < 5; i++)
// {
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(i);
// Time.frameCount.Should().Be(frameCount + i);
// }
//});
//[UnityTest]
//public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
//{
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(0);
// Time.frameCount.Should().Be(frameCount); // same frame
// }
// {
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(0);
// Time.frameCount.Should().Be(frameCount + 1); // next frame
// }
//});
//[UnityTest]
//public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
//});
//[UnityTest]
//public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
//});
//[UnityTest]
//public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame);
// xs[1].Should().Be(initialFrame + 1);
// xs[2].Should().Be(initialFrame + 2);
// xs[3].Should().Be(initialFrame + 3);
// xs[4].Should().Be(initialFrame + 4);
//});
[UnityTest]
public IEnumerator TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
{
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
}
//Debug.Log("------------------");
//{
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
//}
});
//[UnityTest]
//public IEnumerator TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
//{
// {
// var initialFrame = Time.frameCount;
// var xs = await new MyTimerFrame(0, null)/*.Select(_ => Time.frameCount)*/.ToArrayAsync();
// Debug.Log("OK 0 ------------------");
// }
// {
// var xs = await new MyTimerFrame(1, null)/*.Select(_ =>
// {
// var t = Time.frameCount;
// UnityEngine.Debug.Log("store frameCount:" + t);
// return t;
// })*/.ToArrayAsync();
// }
//});
//[UnityTest]
//public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
//{
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.Return(UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None))/*.Select(_ => Time.frameCount)*/.ToArrayAsync();
// xs[0].Should().Be(initialFrame);
// Debug.Log("OK 0 ------------------");
// }
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// Debug.Log("initialFrame:" + initialFrame);
// var xs = await UniTaskAsyncEnumerable.Return(UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None))/*.Select(_ =>
// {
// var t = Time.frameCount;
// UnityEngine.Debug.Log("store frameCount:" + t);
// return t;
// })*/.ToArrayAsync();
// Debug.Log("xs len:" + xs.Length);
// Debug.Log("xs[0]:" + xs[0]);
// xs[0].Should().Be(initialFrame + 1);
// Debug.Log("OK 1");
// }
// {
// //await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// Debug.Log("OK 2");
// }
//});
//[UnityTest]
//public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () =>
//{
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// //var initialFrame = Time.frameCount;
// //var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
// //xs[0].Should().Be(initialFrame);
// }
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 1);
// }
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// }
//});
//[UnityTest]
//public IEnumerator Timer() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// {
// var initialSeconds = Time.realtimeSinceStartup;
// var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync();
// Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse();
// Debug.Log("Init:" + initialSeconds);
// Debug.Log("After:" + xs[0]);
// }
//});
}
public class DelayTest2
{
[UnityTest]
public IEnumerator TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
{
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
}
Debug.Log("------------------");
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
}
});
}
public class ThreadRunner
{
Thread thread;
public void Start(IPlayerLoopItem runner)
{
thread = new Thread(() =>
{
Thread.Sleep(30);
while (runner.MoveNext())
{
Thread.Sleep(30);
}
});
thread.Start();
}
}
internal class MyTimerFrame : IUniTaskAsyncEnumerable<AsyncUnit>
{
//readonly PlayerLoopTiming updateTiming;
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
public MyTimerFrame(int dueTimeFrameCount, int? periodFrameCount)
{
//this.updateTiming = updateTiming;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, cancellationToken);
}
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
CancellationToken cancellationToken;
int initialFrame;
int currentFrame;
bool dueTimePhase;
bool completed;
bool disposed;
ThreadRunner runner;
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, CancellationToken cancellationToken)
{
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
if (periodFrameCount != null)
{
if (periodFrameCount <= 0) periodFrameCount = 1;
}
//this.initialFrame = Time.frameCount;
this.dueTimePhase = true;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
//TaskTracker.TrackActiveTask(this, 2);
//PlayerLoopHelper.AddAction(updateTiming, this);
runner = new ThreadRunner();
runner.Start(this);
}
public AsyncUnit Current => default;
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested || completed) return default;
// reset value here.
this.currentFrame = 0;
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
public UniTask DisposeAsync()
{
if (!disposed)
{
disposed = true;
TaskTracker.RemoveTracking(this);
}
return default;
}
public bool MoveNext()
{
UnityEngine.Debug.Log("Called MoveNext");
if (disposed || cancellationToken.IsCancellationRequested)
{
UnityEngine.Debug.Log("Disposing");
completionSource.TrySetResult(false);
return false;
}
if (dueTimePhase)
{
UnityEngine.Debug.Log("In DueTime Phase");
if (currentFrame == 0)
{
if (dueTimeFrameCount == 0)
{
dueTimePhase = false;
completionSource.TrySetResult(true);
return true;
}
// skip in initial frame.
/*
UnityEngine.Debug.Log("(Init, frameConut)" + (initialFrame, Time.frameCount));
if (initialFrame == Time.frameCount)
{
UnityEngine.Debug.Log("Skip Here");
return true;
}
*/
}
UnityEngine.Debug.Log("Which Go?");
if (++currentFrame >= dueTimeFrameCount)
{
UnityEngine.Debug.Log("END Go?");
dueTimePhase = false;
completionSource.TrySetResult(true);
}
else
{
UnityEngine.Debug.Log("NG Go?");
}
}
else
{
if (periodFrameCount == null)
{
UnityEngine.Debug.Log("PERIOD");
completed = true;
completionSource.TrySetResult(false);
return false;
}
if (++currentFrame >= periodFrameCount)
{
completionSource.TrySetResult(true);
}
}
return true;
}
}
}
}

View File

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

View File

@@ -1,400 +1,400 @@
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2) //#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member //#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine; //using UnityEngine;
using System; //using System;
using System.Collections; //using System.Collections;
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.Text; //using System.Text;
using UnityEngine.UI; //using UnityEngine.UI;
using UnityEngine.Scripting; //using UnityEngine.Scripting;
using Cysharp.Threading.Tasks; //using Cysharp.Threading.Tasks;
using UnityEngine.SceneManagement; //using UnityEngine.SceneManagement;
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) //#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
using System.Threading.Tasks; //using System.Threading.Tasks;
#endif //#endif
using UnityEngine.Networking; //using UnityEngine.Networking;
#if !UNITY_2019_3_OR_NEWER //#if !UNITY_2019_3_OR_NEWER
using UnityEngine.Experimental.LowLevel; //using UnityEngine.Experimental.LowLevel;
#else //#else
using UnityEngine.LowLevel; //using UnityEngine.LowLevel;
#endif //#endif
#if !UNITY_WSA //#if !UNITY_WSA
using Unity.Jobs; //using Unity.Jobs;
#endif //#endif
using Unity.Collections; //using Unity.Collections;
using System.Threading; //using System.Threading;
using NUnit.Framework; //using NUnit.Framework;
using UnityEngine.TestTools; //using UnityEngine.TestTools;
using FluentAssertions; //using FluentAssertions;
namespace Cysharp.Threading.TasksTests //namespace Cysharp.Threading.TasksTests
{ //{
public class AsyncTest // public class AsyncTest
{ // {
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) //#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#if !UNITY_WSA //#if !UNITY_WSA
public struct MyJob : IJob // public struct MyJob : IJob
{ // {
public int loopCount; // public int loopCount;
public NativeArray<int> inOut; // public NativeArray<int> inOut;
public int result; // public int result;
public void Execute() // public void Execute()
{ // {
result = 0; // result = 0;
for (int i = 0; i < loopCount; i++) // for (int i = 0; i < loopCount; i++)
{ // {
result++; // result++;
} // }
inOut[0] = result; // inOut[0] = result;
} // }
} // }
[UnityTest] // [UnityTest]
public IEnumerator DelayAnd() => UniTask.ToCoroutine(async () => // public IEnumerator DelayAnd() => UniTask.ToCoroutine(async () =>
{ // {
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); // await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var time = Time.realtimeSinceStartup; // var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f; // Time.timeScale = 0.5f;
try // try
{ // {
await UniTask.Delay(TimeSpan.FromSeconds(3)); // await UniTask.Delay(TimeSpan.FromSeconds(3));
var elapsed = Time.realtimeSinceStartup - time; // var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(6); // ((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(6);
} // }
finally // finally
{ // {
Time.timeScale = 1.0f; // Time.timeScale = 1.0f;
} // }
}); // });
[UnityTest] // [UnityTest]
public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () => // public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
{ // {
var time = Time.realtimeSinceStartup; // var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f; // Time.timeScale = 0.5f;
try // try
{ // {
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true); // await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);
var elapsed = Time.realtimeSinceStartup - time; // var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3); // ((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
} // }
finally // finally
{ // {
Time.timeScale = 1.0f; // Time.timeScale = 1.0f;
} // }
}); // });
[UnityTest] // [UnityTest]
public IEnumerator WhenAll() => UniTask.ToCoroutine(async () => // public IEnumerator WhenAll() => UniTask.ToCoroutine(async () =>
{ // {
var a = UniTask.FromResult(999); // var a = UniTask.FromResult(999);
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask(); // var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
var c = UniTask.DelayFrame(99).AsAsyncUnitUniTask(); // var c = UniTask.DelayFrame(99).AsAsyncUnitUniTask();
var (a2, b2, c2) = await UniTask.WhenAll(a, b, c); // var (a2, b2, c2) = await UniTask.WhenAll(a, b, c);
a2.Should().Be(999); // a2.Should().Be(999);
b2.Should().Be(AsyncUnit.Default); // b2.Should().Be(AsyncUnit.Default);
c2.Should().Be(AsyncUnit.Default); // c2.Should().Be(AsyncUnit.Default);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator WhenAny() => UniTask.ToCoroutine(async () => // public IEnumerator WhenAny() => UniTask.ToCoroutine(async () =>
{ // {
var a = UniTask.FromResult(999); // var a = UniTask.FromResult(999);
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask(); // var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
var c = UniTask.DelayFrame(99).AsAsyncUnitUniTask(); // var c = UniTask.DelayFrame(99).AsAsyncUnitUniTask();
var (win, a2, b2, c2) = await UniTask.WhenAny(a, b, c); // var (win, a2, b2, c2) = await UniTask.WhenAny(a, b, c);
win.Should().Be(0); // win.Should().Be(0);
a2.Should().Be(999); // a2.Should().Be(999);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () => // public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
{ // {
await ToaruCoroutineEnumerator(); // wait 5 frame:) // await ToaruCoroutineEnumerator(); // wait 5 frame:)
}); // });
[UnityTest] // [UnityTest]
public IEnumerator JobSystem() => UniTask.ToCoroutine(async () => // public IEnumerator JobSystem() => UniTask.ToCoroutine(async () =>
{ // {
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) }; // var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
JobHandle.ScheduleBatchedJobs(); // JobHandle.ScheduleBatchedJobs();
await job.Schedule(); // await job.Schedule();
job.inOut[0].Should().Be(999); // job.inOut[0].Should().Be(999);
job.inOut.Dispose(); // job.inOut.Dispose();
}); // });
class MyMyClass // class MyMyClass
{ // {
public int MyProperty { get; set; } // public int MyProperty { get; set; }
} // }
[UnityTest] // [UnityTest]
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () => // public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
{ // {
bool t = false; // bool t = false;
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); // await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
UniTask.DelayFrame(10,PlayerLoopTiming.PostLateUpdate).ContinueWith(() => t = true).Forget(); // UniTask.DelayFrame(10,PlayerLoopTiming.PostLateUpdate).ContinueWith(() => t = true).Forget();
var startFrame = Time.frameCount; // var startFrame = Time.frameCount;
await UniTask.WaitUntil(() => t, PlayerLoopTiming.EarlyUpdate); // await UniTask.WaitUntil(() => t, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame; // var diff = Time.frameCount - startFrame;
diff.Should().Be(11); // diff.Should().Be(11);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () => // public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
{ // {
bool t = true; // bool t = true;
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => t = false).Forget(); // UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => t = false).Forget();
var startFrame = Time.frameCount; // var startFrame = Time.frameCount;
await UniTask.WaitWhile(() => t, PlayerLoopTiming.EarlyUpdate); // await UniTask.WaitWhile(() => t, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame; // var diff = Time.frameCount - startFrame;
diff.Should().Be(11); // diff.Should().Be(11);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () => // public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
{ // {
var v = new MyMyClass { MyProperty = 99 }; // var v = new MyMyClass { MyProperty = 99 };
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = 1000).Forget(); // UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = 1000).Forget();
var startFrame = Time.frameCount; // var startFrame = Time.frameCount;
await UniTask.WaitUntilValueChanged(v, x => x.MyProperty, PlayerLoopTiming.EarlyUpdate); // await UniTask.WaitUntilValueChanged(v, x => x.MyProperty, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame; // var diff = Time.frameCount - startFrame;
diff.Should().Be(11); // diff.Should().Be(11);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator SwitchTo() => UniTask.ToCoroutine(async () => // public IEnumerator SwitchTo() => UniTask.ToCoroutine(async () =>
{ // {
await UniTask.Yield(); // await UniTask.Yield();
var currentThreadId = Thread.CurrentThread.ManagedThreadId; // var currentThreadId = Thread.CurrentThread.ManagedThreadId;
await UniTask.SwitchToThreadPool(); // await UniTask.SwitchToThreadPool();
//await UniTask.SwitchToThreadPool(); // //await UniTask.SwitchToThreadPool();
//await UniTask.SwitchToThreadPool(); // //await UniTask.SwitchToThreadPool();
var switchedThreadId = Thread.CurrentThread.ManagedThreadId; // var switchedThreadId = Thread.CurrentThread.ManagedThreadId;
currentThreadId.Should().NotBe(switchedThreadId); // currentThreadId.Should().NotBe(switchedThreadId);
await UniTask.Yield(); // await UniTask.Yield();
var switchedThreadId2 = Thread.CurrentThread.ManagedThreadId; // var switchedThreadId2 = Thread.CurrentThread.ManagedThreadId;
currentThreadId.Should().Be(switchedThreadId2); // currentThreadId.Should().Be(switchedThreadId2);
}); // });
//[UnityTest] // //[UnityTest]
//public IEnumerator ObservableConversion() => UniTask.ToCoroutine(async () => // //public IEnumerator ObservableConversion() => UniTask.ToCoroutine(async () =>
//{ // //{
// var v = await Observable.Range(1, 10).ToUniTask(); // // var v = await Observable.Range(1, 10).ToUniTask();
// v.Is(10); // // v.Is(10);
// v = await Observable.Range(1, 10).ToUniTask(useFirstValue: true); // // v = await Observable.Range(1, 10).ToUniTask(useFirstValue: true);
// v.Is(1); // // v.Is(1);
// v = await UniTask.DelayFrame(10).ToObservable().ToTask(); // // v = await UniTask.DelayFrame(10).ToObservable().ToTask();
// v.Is(10); // // v.Is(10);
// v = await UniTask.FromResult(99).ToObservable(); // // v = await UniTask.FromResult(99).ToObservable();
// v.Is(99); // // v.Is(99);
//}); // //});
//[UnityTest] // //[UnityTest]
//public IEnumerator AwaitableReactiveProperty() => UniTask.ToCoroutine(async () => // //public IEnumerator AwaitableReactiveProperty() => UniTask.ToCoroutine(async () =>
//{ // //{
// var rp1 = new ReactiveProperty<int>(99); // // var rp1 = new ReactiveProperty<int>(99);
// UniTask.DelayFrame(100).ContinueWith(x => rp1.Value = x).Forget(); // // UniTask.DelayFrame(100).ContinueWith(x => rp1.Value = x).Forget();
// await rp1; // // await rp1;
// rp1.Value.Is(100); // // rp1.Value.Is(100);
// // var delay2 = UniTask.DelayFrame(10); // // // var delay2 = UniTask.DelayFrame(10);
// // var (a, b ) = await UniTask.WhenAll(rp1.WaitUntilValueChangedAsync(), delay2); // // // var (a, b ) = await UniTask.WhenAll(rp1.WaitUntilValueChangedAsync(), delay2);
//}); // //});
//[UnityTest] // //[UnityTest]
//public IEnumerator AwaitableReactiveCommand() => UniTask.ToCoroutine(async () => // //public IEnumerator AwaitableReactiveCommand() => UniTask.ToCoroutine(async () =>
//{ // //{
// var rc = new ReactiveCommand<int>(); // // var rc = new ReactiveCommand<int>();
// UniTask.DelayFrame(100).ContinueWith(x => rc.Execute(x)).Forget(); // // UniTask.DelayFrame(100).ContinueWith(x => rc.Execute(x)).Forget();
// var v = await rc; // // var v = await rc;
// v.Is(100); // // v.Is(100);
//}); // //});
[UnityTest] // [UnityTest]
public IEnumerator ExceptionlessCancellation() => UniTask.ToCoroutine(async () => // public IEnumerator ExceptionlessCancellation() => UniTask.ToCoroutine(async () =>
{ // {
var cts = new CancellationTokenSource(); // var cts = new CancellationTokenSource();
UniTask.DelayFrame(10).ContinueWith(() => cts.Cancel()).Forget(); // UniTask.DelayFrame(10).ContinueWith(() => cts.Cancel()).Forget();
var first = Time.frameCount; // var first = Time.frameCount;
var canceled = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow(); // var canceled = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow();
(Time.frameCount - first).Should().Be(11); // 10 frame canceled // (Time.frameCount - first).Should().Be(11); // 10 frame canceled
canceled.Should().Be(true); // canceled.Should().Be(true);
}); // });
[UnityTest] // [UnityTest]
public IEnumerator ExceptionCancellation() => UniTask.ToCoroutine(async () => // public IEnumerator ExceptionCancellation() => UniTask.ToCoroutine(async () =>
{ // {
var cts = new CancellationTokenSource(); // var cts = new CancellationTokenSource();
UniTask.DelayFrame(10).ContinueWith(() => cts.Cancel()).Forget(); // UniTask.DelayFrame(10).ContinueWith(() => cts.Cancel()).Forget();
bool occur = false; // bool occur = false;
try // try
{ // {
await UniTask.DelayFrame(100, cancellationToken: cts.Token); // await UniTask.DelayFrame(100, cancellationToken: cts.Token);
} // }
catch (OperationCanceledException) // catch (OperationCanceledException)
{ // {
occur = true; // occur = true;
} // }
occur.Should().BeTrue(); // occur.Should().BeTrue();
}); // });
IEnumerator ToaruCoroutineEnumerator() // IEnumerator ToaruCoroutineEnumerator()
{ // {
yield return null; // yield return null;
yield return null; // yield return null;
yield return null; // yield return null;
yield return null; // yield return null;
yield return null; // yield return null;
} // }
[UnityTest] // [UnityTest]
public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () => // public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () =>
{ // {
bool calledEx = false; // bool calledEx = false;
Action<Exception> action = exx => // Action<Exception> action = exx =>
{ // {
calledEx = true; // calledEx = true;
exx.Message.Should().Be("MyException"); // exx.Message.Should().Be("MyException");
}; // };
UniTaskScheduler.UnobservedTaskException += action; // UniTaskScheduler.UnobservedTaskException += action;
var ex = InException1(); // var ex = InException1();
ex = default(UniTask); // ex = default(UniTask);
await UniTask.DelayFrame(3); // await UniTask.DelayFrame(3);
GC.Collect(); // GC.Collect();
GC.WaitForPendingFinalizers(); // GC.WaitForPendingFinalizers();
GC.Collect(); // GC.Collect();
await UniTask.DelayFrame(1); // await UniTask.DelayFrame(1);
calledEx.Should().BeTrue(); // calledEx.Should().BeTrue();
UniTaskScheduler.UnobservedTaskException -= action; // UniTaskScheduler.UnobservedTaskException -= action;
}); // });
[UnityTest] // [UnityTest]
public IEnumerator ExceptionUnobserved2() => UniTask.ToCoroutine(async () => // public IEnumerator ExceptionUnobserved2() => UniTask.ToCoroutine(async () =>
{ // {
bool calledEx = false; // bool calledEx = false;
Action<Exception> action = exx => // Action<Exception> action = exx =>
{ // {
calledEx = true; // calledEx = true;
exx.Message.Should().Be("MyException"); // exx.Message.Should().Be("MyException");
}; // };
UniTaskScheduler.UnobservedTaskException += action; // UniTaskScheduler.UnobservedTaskException += action;
var ex = InException2(); // var ex = InException2();
ex = default(UniTask<int>); // ex = default(UniTask<int>);
await UniTask.DelayFrame(3); // await UniTask.DelayFrame(3);
GC.Collect(); // GC.Collect();
GC.WaitForPendingFinalizers(); // GC.WaitForPendingFinalizers();
GC.Collect(); // GC.Collect();
await UniTask.DelayFrame(1); // await UniTask.DelayFrame(1);
calledEx.Should().BeTrue(); // calledEx.Should().BeTrue();
UniTaskScheduler.UnobservedTaskException -= action; // UniTaskScheduler.UnobservedTaskException -= action;
}); // });
async UniTask InException1() // async UniTask InException1()
{ // {
await UniTask.Yield(); // await UniTask.Yield();
throw new Exception("MyException"); // throw new Exception("MyException");
} // }
async UniTask<int> InException2() // async UniTask<int> InException2()
{ // {
await UniTask.Yield(); // await UniTask.Yield();
throw new Exception("MyException"); // throw new Exception("MyException");
} // }
[UnityTest] // [UnityTest]
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () => // public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
{ // {
var time = Time.realtimeSinceStartup; // var time = Time.realtimeSinceStartup;
await ParentCoroutineEnumerator(); // await ParentCoroutineEnumerator();
var elapsed = Time.realtimeSinceStartup - time; // var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3); // ((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
}); // });
IEnumerator ParentCoroutineEnumerator() // IEnumerator ParentCoroutineEnumerator()
{ // {
yield return ChildCoroutineEnumerator(); // yield return ChildCoroutineEnumerator();
} // }
IEnumerator ChildCoroutineEnumerator() // IEnumerator ChildCoroutineEnumerator()
{ // {
yield return new WaitForSeconds(3); // yield return new WaitForSeconds(3);
} // }
#endif //#endif
#endif //#endif
} // }
} //}
#endif //#endif

View File

@@ -1,95 +1,95 @@
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2) //#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member //#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine; //using UnityEngine;
using System; //using System;
using System.Collections; //using System.Collections;
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.Text; //using System.Text;
using UnityEngine.UI; //using UnityEngine.UI;
using UnityEngine.Scripting; //using UnityEngine.Scripting;
using Cysharp.Threading.Tasks; //using Cysharp.Threading.Tasks;
using UnityEngine.SceneManagement; //using UnityEngine.SceneManagement;
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) //#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
using System.Threading.Tasks; //using System.Threading.Tasks;
#endif //#endif
using UnityEngine.Networking; //using UnityEngine.Networking;
#if !UNITY_2019_3_OR_NEWER //#if !UNITY_2019_3_OR_NEWER
using UnityEngine.Experimental.LowLevel; //using UnityEngine.Experimental.LowLevel;
#else //#else
using UnityEngine.LowLevel; //using UnityEngine.LowLevel;
#endif //#endif
#if !UNITY_WSA //#if !UNITY_WSA
using Unity.Jobs; //using Unity.Jobs;
#endif //#endif
using Unity.Collections; //using Unity.Collections;
using System.Threading; //using System.Threading;
using NUnit.Framework; //using NUnit.Framework;
using UnityEngine.TestTools; //using UnityEngine.TestTools;
using FluentAssertions; //using FluentAssertions;
namespace Cysharp.Threading.TasksTests //namespace Cysharp.Threading.TasksTests
{ //{
public class RunTest // public class RunTest
{ // {
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) //#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#if !UNITY_WSA //#if !UNITY_WSA
//[UnityTest] // //[UnityTest]
//public IEnumerator RunThread() => UniTask.ToCoroutine(async () => // //public IEnumerator RunThread() => UniTask.ToCoroutine(async () =>
//{ // //{
// var main = Thread.CurrentThread.ManagedThreadId; // // var main = Thread.CurrentThread.ManagedThreadId;
// var v = await UniTask.Run(() => { return System.Threading.Thread.CurrentThread.ManagedThreadId; }, false); // // var v = await UniTask.Run(() => { return System.Threading.Thread.CurrentThread.ManagedThreadId; }, false);
// UnityEngine.Debug.Log("Ret Value is:" + v); // // UnityEngine.Debug.Log("Ret Value is:" + v);
// UnityEngine.Debug.Log("Run Here and id:" + System.Threading.Thread.CurrentThread.ManagedThreadId); // // UnityEngine.Debug.Log("Run Here and id:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
// //v.Should().Be(3); // // //v.Should().Be(3);
// main.Should().NotBe(Thread.CurrentThread.ManagedThreadId); // // main.Should().NotBe(Thread.CurrentThread.ManagedThreadId);
//}); // //});
[UnityTest] // [UnityTest]
public IEnumerator RunThreadConfigure() => UniTask.ToCoroutine(async () => // public IEnumerator RunThreadConfigure() => UniTask.ToCoroutine(async () =>
{ // {
var main = Thread.CurrentThread.ManagedThreadId; // var main = Thread.CurrentThread.ManagedThreadId;
var v = await UniTask.Run(() => 3, true); // var v = await UniTask.Run(() => 3, true);
v.Should().Be(3); // v.Should().Be(3);
main.Should().Be(Thread.CurrentThread.ManagedThreadId); // main.Should().Be(Thread.CurrentThread.ManagedThreadId);
}); // });
//[UnityTest] // //[UnityTest]
//public IEnumerator RunThreadException() => UniTask.ToCoroutine(async () => // //public IEnumerator RunThreadException() => UniTask.ToCoroutine(async () =>
//{ // //{
// var main = Thread.CurrentThread.ManagedThreadId; // // var main = Thread.CurrentThread.ManagedThreadId;
// try // // try
// { // // {
// await UniTask.Run<int>(() => throw new Exception(), false); // // await UniTask.Run<int>(() => throw new Exception(), false);
// } // // }
// catch // // catch
// { // // {
// main.Should().NotBe(Thread.CurrentThread.ManagedThreadId); // // main.Should().NotBe(Thread.CurrentThread.ManagedThreadId);
// } // // }
//}); // //});
[UnityTest] // [UnityTest]
public IEnumerator RunThreadExceptionConfigure() => UniTask.ToCoroutine(async () => // public IEnumerator RunThreadExceptionConfigure() => UniTask.ToCoroutine(async () =>
{ // {
var main = Thread.CurrentThread.ManagedThreadId; // var main = Thread.CurrentThread.ManagedThreadId;
try // try
{ // {
await UniTask.Run<int>(() => throw new Exception(), true); // await UniTask.Run<int>(() => throw new Exception(), true);
} // }
catch // catch
{ // {
main.Should().Be(Thread.CurrentThread.ManagedThreadId); // main.Should().Be(Thread.CurrentThread.ManagedThreadId);
} // }
}); // });
#endif //#endif
#endif //#endif
} // }
} //}
#endif //#endif

View File

@@ -1,43 +1,43 @@
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) //#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member //#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine; //using UnityEngine;
using System; //using System;
using System.Collections; //using System.Collections;
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.Text; //using System.Text;
using UnityEngine.UI; //using UnityEngine.UI;
using UnityEngine.Scripting; //using UnityEngine.Scripting;
using Cysharp.Threading.Tasks; //using Cysharp.Threading.Tasks;
using Unity.Collections; //using Unity.Collections;
using System.Threading; //using System.Threading;
using NUnit.Framework; //using NUnit.Framework;
using UnityEngine.TestTools; //using UnityEngine.TestTools;
using FluentAssertions; //using FluentAssertions;
namespace Cysharp.Threading.TasksTests //namespace Cysharp.Threading.TasksTests
{ //{
public class WhenAnyTest // public class WhenAnyTest
{ // {
[UnityTest] // [UnityTest]
public IEnumerator WhenAnyCanceled() => UniTask.ToCoroutine(async () => // public IEnumerator WhenAnyCanceled() => UniTask.ToCoroutine(async () =>
{ // {
var cts = new CancellationTokenSource(); // var cts = new CancellationTokenSource();
var successDelayTask = UniTask.Delay(TimeSpan.FromSeconds(1)); // var successDelayTask = UniTask.Delay(TimeSpan.FromSeconds(1));
var cancelTask = UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: cts.Token); // var cancelTask = UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: cts.Token);
cts.CancelAfterSlim(200); // cts.CancelAfterSlim(200);
try // try
{ // {
var r = await UniTask.WhenAny(new[] { successDelayTask, cancelTask }); // var r = await UniTask.WhenAny(new[] { successDelayTask, cancelTask });
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
ex.Should().BeAssignableTo<OperationCanceledException>(); // ex.Should().BeAssignableTo<OperationCanceledException>();
} // }
}); // });
} // }
} //}
#endif //#endif

View File

@@ -6,13 +6,20 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.TestTools; using UnityEngine.TestTools;
namespace Cysharp.Threading.TasksTests namespace Cysharp.Threading.TasksTests
{ {
public class Preserve public class Preserve
{ {
public Preserve()
{
// TaskPool.SetMaxPoolSize(0);
}
[UnityTest] [UnityTest]
public IEnumerator AwaitTwice() => UniTask.ToCoroutine(async () => public IEnumerator AwaitTwice() => UniTask.ToCoroutine(async () =>
{ {
@@ -33,12 +40,17 @@ namespace Cysharp.Threading.TasksTests
[UnityTest] [UnityTest]
public IEnumerator PreserveAllowTwice() => UniTask.ToCoroutine(async () => public IEnumerator PreserveAllowTwice() => UniTask.ToCoroutine(async () =>
{ {
await UniTask.Yield(PlayerLoopTiming.Update);
var delay = UniTask.DelayFrame(5, PlayerLoopTiming.PostLateUpdate).Preserve(); var delay = UniTask.DelayFrame(5, PlayerLoopTiming.PostLateUpdate).Preserve();
var before = UnityEngine.Time.frameCount;
var before = UnityEngine.Time.frameCount; // 0
await delay; await delay;
var afterOne = UnityEngine.Time.frameCount; var afterOne = UnityEngine.Time.frameCount; // 5
await delay; await delay;
var afterTwo = UnityEngine.Time.frameCount; var afterTwo = UnityEngine.Time.frameCount; // 5
(afterOne - before).Should().Be(5); (afterOne - before).Should().Be(5);
afterOne.Should().Be(afterTwo); afterOne.Should().Be(afterTwo);

View File

@@ -5,7 +5,8 @@
"UnityEditor.TestRunner", "UnityEditor.TestRunner",
"UniTask", "UniTask",
"Unity.ResourceManager", "Unity.ResourceManager",
"DOTween.Modules" "DOTween.Modules",
"UniTask.Linq"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@@ -8,7 +8,7 @@ EditorBuildSettings:
- enabled: 1 - enabled: 1
path: Assets/Scenes/SandboxMain.unity path: Assets/Scenes/SandboxMain.unity
guid: 2cda990e2423bbf4892e6590ba056729 guid: 2cda990e2423bbf4892e6590ba056729
- enabled: 0 - enabled: 1
path: path: Assets/Scenes/ExceptionExamples.unity
guid: 00000000000000000000000000000000 guid: b5fed17e3ece238439bc796d8747df5d
m_configObjects: {} m_configObjects: {}