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.
- uses: actions/upload-artifact@v2
with:
name: UniTask.unitypackage.zip
path: ./src/UniTask/*.unitypackage
name: UniTask.${{ env.GIT_TAG }}.unitypackage
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
create-release:
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.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
* 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
* Completely run on Unity's PlayerLoop so don't use thread and run on WebGL, wasm, etc.
* Asynchronous LINQ, with Channel and AsyncReactiveProperty
@@ -29,6 +29,7 @@ Provides an efficient async/await integration to Unity.
- [Awaitable Events](#awaitable-events)
- [Channel](#channel)
- [For Unit Testing](#for-unit-testing)
- [Pooling Configuration](#pooling-configuration)
- [API References](#api-references)
- [UPM Package](#upm-package)
- [Install via git URL](#install-via-git-url)
@@ -52,21 +53,33 @@ async UniTask<string> DemoAsync()
{
// You can await Unity's AsyncObject
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
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>
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 UniTask.DelayFrame(100);
// replacement of WaitForSeconds/WaitForSecondsRealtime
// replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
// replacement of WaitForEndOfFrame(or other timing like yield return null, yield return WaitForFixedUpdate)
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
// yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)
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
await UniTask.WaitUntil(() => isActive == false);
@@ -80,9 +93,14 @@ async UniTask<string> DemoAsync()
// You can await standard task
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();
/* work on ThreadPool */
// return to MainThread(same as `ObserveOnMainThread` in UniRx)
await UniTask.SwitchToMainThread();
// get async webrequest
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.
> 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.
```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.
`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)]`.
@@ -413,7 +443,7 @@ For debug use, enable tracking and capture stacktrace is useful but it it declin
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.
@@ -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.
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
---
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.
@@ -714,4 +767,4 @@ Utility methods such as WhenAll which is equivalent to UniTask are provided as [
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
using System;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace Cysharp.Threading.Tasks
{
@@ -8,12 +10,20 @@ namespace Cysharp.Threading.Tasks
{
public static ValueTask AsValueTask(this in UniTask task)
{
#if NETSTANDARD2_0
return new ValueTask(new UniTaskValueTaskSource(task), 0);
#else
return task;
#endif
}
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;
#endif
}
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);
}
#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">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netstandard2.1</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0</TargetFrameworks>
<AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>

View File

@@ -277,7 +277,11 @@ namespace NetCoreSandbox
#endif
// 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();
SynchronizationContext.SetSynchronizationContext(new MySyncContext());

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder
{
internal IStateMachineRunnerPromise runnerPromise;
IStateMachineRunnerPromise runnerPromise;
Exception ex;
// 1. Static Create method.
@@ -80,7 +80,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.OnCompleted(runnerPromise.MoveNext);
@@ -96,7 +96,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
@@ -138,7 +138,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder<T>
{
internal IStateMachineRunnerPromise<T> runnerPromise;
IStateMachineRunnerPromise<T> runnerPromise;
Exception ex;
T result;
@@ -211,7 +211,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.OnCompleted(runnerPromise.MoveNext);
@@ -227,7 +227,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);

View File

@@ -12,7 +12,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskVoidMethodBuilder
{
internal IStateMachineRunner runner;
IStateMachineRunner runner;
// 1. Static Create method.
[DebuggerHidden]
@@ -70,7 +70,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runner == null)
{
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
}
awaiter.OnCompleted(runner.MoveNext);
@@ -86,7 +86,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
if (runner == null)
{
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
}
awaiter.UnsafeOnCompleted(runner.MoveNext);

View File

@@ -2,6 +2,7 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Linq;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -29,12 +30,26 @@ namespace Cysharp.Threading.Tasks.CompilerServices
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
where TStateMachine : IAsyncStateMachine
{
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
#if ENABLE_IL2CPP
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine;
#endif
public Action MoveNext { get; }
@@ -43,7 +58,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
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))
{
@@ -51,7 +66,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
}
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).
}
@@ -102,7 +117,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
static TaskPool<AsyncUniTask<TStateMachine>> pool;
#if ENABLE_IL2CPP
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine;
#endif
public Action MoveNext { get; }
@@ -113,7 +132,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
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))
{
@@ -121,7 +140,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
}
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).
}
@@ -213,7 +232,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
#if ENABLE_IL2CPP
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
#else
TStateMachine stateMachine;
#endif
public Action MoveNext { get; }
@@ -224,7 +247,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
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))
{
@@ -232,10 +255,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
}
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).
// UnityEngine.Debug.Log($"SetStateMachine State:" + StateMachineUtility.GetState(stateMachine));
}
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
static AsyncUniTask()
@@ -255,6 +281,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
stateMachine.MoveNext();
}

View File

@@ -12,10 +12,12 @@ namespace Cysharp.Threading.Tasks
{
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));
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
var e = (IEnumerator)enumerator;
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)

View File

@@ -23,7 +23,7 @@ namespace Cysharp.Threading.Tasks
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
{
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))
@@ -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>
{
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
@@ -210,7 +336,7 @@ namespace Cysharp.Threading.Tasks
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
{
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))
@@ -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>>
{
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;

View File

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

View File

@@ -19,7 +19,7 @@ namespace Cysharp.Threading.Tasks
// similar as IValueTaskSource
public interface IUniTaskSource
#if !UNITY_2018_3_OR_NEWER
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
: System.Threading.Tasks.Sources.IValueTaskSource
#pragma warning disable CS0108
#endif
@@ -30,7 +30,7 @@ namespace Cysharp.Threading.Tasks
UniTaskStatus UnsafeGetStatus(); // only for debug use.
#if !UNITY_2018_3_OR_NEWER
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#pragma warning restore CS0108
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
#if !UNITY_2018_3_OR_NEWER
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
, System.Threading.Tasks.Sources.IValueTaskSource<T>
#endif
{
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)
{

View File

@@ -239,7 +239,7 @@ namespace Cysharp.Threading.Tasks.Internal
}
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;
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)
{
// UnityEngine.Debug.Log("Called ToArray");
var pool = ArrayPool<TSource>.Shared;
var array = pool.Rent(16);

View File

@@ -1,5 +1,6 @@
using System;
using System.Threading;
using UnityEngine;
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)
{
if (dueTimeFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, null, updateTiming);
}
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);
}
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);
}
}
@@ -64,6 +83,7 @@ namespace Cysharp.Threading.Tasks.Linq
readonly bool ignoreTimeScale;
CancellationToken cancellationToken;
int initialFrame;
float elapsed;
bool dueTimePhase;
bool completed;
@@ -80,6 +100,7 @@ namespace Cysharp.Threading.Tasks.Linq
if (this.period <= 0) this.period = 1;
}
this.initialFrame = Time.frameCount;
this.dueTimePhase = true;
this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale;
@@ -119,9 +140,19 @@ namespace Cysharp.Threading.Tasks.Linq
return false;
}
elapsed += (ignoreTimeScale) ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
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)
{
dueTimePhase = false;
@@ -137,6 +168,8 @@ namespace Cysharp.Threading.Tasks.Linq
return false;
}
elapsed += (ignoreTimeScale) ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
if (elapsed >= period)
{
completionSource.TrySetResult(true);
@@ -172,6 +205,7 @@ namespace Cysharp.Threading.Tasks.Linq
readonly int? periodFrameCount;
CancellationToken cancellationToken;
int initialFrame;
int currentFrame;
bool dueTimePhase;
bool completed;
@@ -185,6 +219,7 @@ namespace Cysharp.Threading.Tasks.Linq
if (periodFrameCount <= 0) periodFrameCount = 1;
}
this.initialFrame = Time.frameCount;
this.dueTimePhase = true;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
@@ -228,11 +263,30 @@ namespace Cysharp.Threading.Tasks.Linq
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;
completionSource.TrySetResult(true);
}
else
{
}
}
else
{

View File

@@ -92,8 +92,10 @@ namespace Cysharp.Threading.Tasks
{
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext;
public static int MainThreadId => mainThreadId;
internal static string ApplicationDataPath => applicationDataPath;
static int mainThreadId;
static string applicationDataPath;
static SynchronizationContext unitySynchronizationContetext;
static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners;
@@ -177,6 +179,11 @@ namespace Cysharp.Threading.Tasks
// capture default(unity) sync-context.
unitySynchronizationContetext = SynchronizationContext.Current;
mainThreadId = Thread.CurrentThread.ManagedThreadId;
try
{
applicationDataPath = Application.dataPath;
}
catch { }
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
// When domain reload is disabled, re-initialization is required when entering play mode;

View File

@@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
using UnityEngine;
namespace Cysharp.Threading.Tasks
@@ -21,6 +20,46 @@ namespace Cysharp.Threading.Tasks
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))
{
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;
public DelayFramePromise NextNode { get; set; }
static TaskPool<NextFramePromise> pool;
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;
UniTaskCompletionSourceCore<AsyncUnit> core;
int currentFrameCount;
UniTaskCompletionSourceCore<object> core;
DelayFramePromise()
NextFramePromise()
{
}
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)
{
@@ -181,10 +218,10 @@ namespace Cysharp.Threading.Tasks
if (!pool.TryPop(out var result))
{
result = new DelayFramePromise();
result = new NextFramePromise();
}
result.delayFrameCount = delayFrameCount;
result.frameCount = Time.frameCount;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
@@ -230,13 +267,133 @@ namespace Cysharp.Threading.Tasks
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;
}
currentFrameCount++;
return true;
}
@@ -269,6 +426,7 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size);
}
int initialFrame;
float delayFrameTimeSpan;
float elapsed;
CancellationToken cancellationToken;
@@ -294,6 +452,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken;
result.initialFrame = Time.frameCount;
TaskTracker.TrackActiveTask(result, 3);
@@ -338,6 +497,14 @@ namespace Cysharp.Threading.Tasks
return false;
}
if (elapsed == 0.0f)
{
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += Time.deltaTime;
if (elapsed >= delayFrameTimeSpan)
{
@@ -379,6 +546,7 @@ namespace Cysharp.Threading.Tasks
float delayFrameTimeSpan;
float elapsed;
int initialFrame;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<object> core;
@@ -401,6 +569,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.initialFrame = Time.frameCount;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
@@ -446,6 +615,14 @@ namespace Cysharp.Threading.Tasks
return false;
}
if (elapsed == 0.0f)
{
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += Time.unscaledDeltaTime;
if (elapsed >= delayFrameTimeSpan)
{

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,7 +25,7 @@ namespace Cysharp.Threading.Tasks
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
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))
@@ -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;
public AsyncOperationConfiguredSource NextNode { get; set; }
@@ -124,7 +244,6 @@ namespace Cysharp.Threading.Tasks
{
try
{
core.GetResult(token);
}
finally
@@ -133,6 +252,7 @@ namespace Cysharp.Threading.Tasks
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
@@ -203,7 +323,7 @@ namespace Cysharp.Threading.Tasks
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, 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))
@@ -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;
public ResourceRequestConfiguredSource NextNode { get; set; }
@@ -306,7 +550,6 @@ namespace Cysharp.Threading.Tasks
{
try
{
return core.GetResult(token);
}
finally
@@ -390,7 +633,7 @@ namespace Cysharp.Threading.Tasks
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, cancellationToken, 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))
@@ -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;
public AssetBundleRequestConfiguredSource NextNode { get; set; }
@@ -545,11 +912,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
progress = default;
cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this);
}
@@ -576,7 +943,7 @@ namespace Cysharp.Threading.Tasks
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
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))
@@ -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;
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
@@ -731,11 +1222,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
progress = default;
cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this);
}
@@ -763,7 +1254,7 @@ namespace Cysharp.Threading.Tasks
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
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))
@@ -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;
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
@@ -866,7 +1482,6 @@ namespace Cysharp.Threading.Tasks
{
try
{
return core.GetResult(token);
}
finally
@@ -920,11 +1535,11 @@ namespace Cysharp.Threading.Tasks
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
progress = default;
cancellationToken = default;
TaskTracker.RemoveTracking(this);
return pool.TryPush(this);
}

View File

@@ -37,7 +37,7 @@ namespace Cysharp.Threading.Tasks
<# if(t.returnType == "UnityWebRequest") { #>
#if ENABLE_UNITYWEBREQUEST
<# } #>
#region <#= t.typeName #>
#region <#= t.typeName #>
public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation)
{
@@ -45,18 +45,18 @@ namespace Cysharp.Threading.Tasks
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));
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token);
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
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));
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token);
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, cancellationToken, out var token), token);
}
public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion
@@ -106,14 +106,153 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
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;
IProgress<float> progress;
@@ -133,7 +272,10 @@ namespace Cysharp.Threading.Tasks
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.progress = progress;
@@ -151,8 +293,6 @@ namespace Cysharp.Threading.Tasks
{
try
{
TaskTracker.RemoveTracking(this);
<# if (!IsVoid(t)) { #>
return core.GetResult(token);
<# } else { #>
@@ -161,7 +301,7 @@ namespace Cysharp.Threading.Tasks
}
finally
{
pool.TryReturn(this);
TryReturn();
}
}
@@ -191,6 +331,9 @@ namespace Cysharp.Threading.Tasks
{
if (cancellationToken.IsCancellationRequested)
{
<# if(t.returnType == "UnityWebRequest") { #>
asyncOperation.webRequest.Abort();
<# } #>
core.TrySetCanceled(cancellationToken);
return false;
}
@@ -209,24 +352,26 @@ namespace Cysharp.Threading.Tasks
return true;
}
public void Reset()
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation = default;
progress = default;
cancellationToken = default;
return pool.TryPush(this);
}
~<#= t.typeName #>ConfiguredSource()
{
if (pool.TryReturn(this))
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
# endregion
#endregion
<# if(t.returnType == "UnityWebRequest") { #>
#endif
<# } #>

View File

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

View File

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

View File

@@ -14,6 +14,8 @@ using UnityEngine;
using UnityEngine.LowLevel;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
// using DG.Tweening;
@@ -264,11 +266,14 @@ public class SandboxMain : MonoBehaviour
//var r = UniAsync("https://bing.com/", cts.Token);
//cts.Cancel();
//await r;
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
Debug.Log("UNIASYNC1 ");
Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType);
_ = 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
{
@@ -301,10 +306,210 @@ public class SandboxMain : MonoBehaviour
return 10;
}
async UniTaskVoid Start()
async UniTask<int> Ex()
{
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)
// .Do(_ => { }, () => Debug.Log("COMPLETED"))
@@ -315,10 +520,29 @@ public class SandboxMain : MonoBehaviour
// .Forget();
//_ = Test1();
Test2().Forget();
//Test2().Forget();
//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>
//Debug.Log("GO MOVEX");
//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);
//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 () =>
{
await UniTask.Yield();
Debug.Log("Yeha");
}));
//foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
//{
// Debug.Log(type + ":" + size);
//}
//}).Forget();
@@ -396,7 +619,7 @@ public class SandboxMain : MonoBehaviour
//okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
PlayerLoopInfo.Inject();
//UpdateUniTask().Forget();
@@ -405,15 +628,21 @@ public class SandboxMain : MonoBehaviour
//await UniTask.Delay(TimeSpan.FromSeconds(1));
_ = ReturnToMainThreadTest();
// _ = ReturnToMainThreadTest();
//GameObject.Destroy(this.gameObject);
SynchronizationContext.Current.Post(_ =>
{
//UnityEngine.Debug.Log("Post:" + PlayerLoopInfo.CurrentLoopType);
}, null);
}
private void Application_logMessageReceived2(string condition, string stackTrace, LogType type)
{
throw new NotImplementedException();
}
private void Application_logMessageReceived1(string condition, string stackTrace, LogType type)
{
throw new NotImplementedException();
}
async UniTaskVoid UpdateUniTask()

View File

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

View File

@@ -6,13 +6,20 @@ 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 Preserve
{
public Preserve()
{
// TaskPool.SetMaxPoolSize(0);
}
[UnityTest]
public IEnumerator AwaitTwice() => UniTask.ToCoroutine(async () =>
{
@@ -33,12 +40,17 @@ namespace Cysharp.Threading.TasksTests
[UnityTest]
public IEnumerator PreserveAllowTwice() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.Update);
var delay = UniTask.DelayFrame(5, PlayerLoopTiming.PostLateUpdate).Preserve();
var before = UnityEngine.Time.frameCount;
var before = UnityEngine.Time.frameCount; // 0
await delay;
var afterOne = UnityEngine.Time.frameCount;
var afterOne = UnityEngine.Time.frameCount; // 5
await delay;
var afterTwo = UnityEngine.Time.frameCount;
var afterTwo = UnityEngine.Time.frameCount; // 5
(afterOne - before).Should().Be(5);
afterOne.Should().Be(afterTwo);

View File

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

View File

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