Compare commits

..

1 Commits

Author SHA1 Message Date
Ikiru Yoshizaki
51cc6e71e9 chore: add demo script which follows README 2021-04-27 10:43:58 +09:00
82 changed files with 3869 additions and 3597 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
github: [neuecc]

View File

@@ -4,6 +4,8 @@ on:
push:
branches:
- "master"
tags:
- "!*" # not a tag push
pull_request:
branches:
- "master"
@@ -11,56 +13,70 @@ on:
jobs:
build-dotnet:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
- uses: actions/checkout@v3
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: dotnet build -c Debug
- run: dotnet test -c Debug
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.x
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
build-unity:
if: "((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
strategy:
matrix:
unity: ["2019.3.9f1", "2019.4.13f1", "2020.1.12f1"]
include:
- unity: 2019.3.9f1
license: UNITY_LICENSE_2019
- unity: 2019.4.13f1
license: UNITY_LICENSE_2019
- unity: 2020.1.12f1
license: UNITY_LICENSE_2020
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
# Execute scripts: RuntimeUnitTestToolkit
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend mono /BuildTarget StandaloneLinux64
- name: Build UnitTest(Linux64, mono)
uses: Cysharp/Actions/.github/actions/unity-builder@main
uses: game-ci/unity-builder@v2.0-alpha-6
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_LICENSE: ${{ secrets[matrix.license] }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: UnitTestBuilder.BuildUnitTest
customParameters: /headless /ScriptBackend mono
versioning: None
- name: Execute UnitTest
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_Mono2x/test
# Execute scripts: Export Package
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- name: Build Unity (.unitypacakge)
uses: Cysharp/Actions/.github/actions/unity-builder@main
- name: Export unitypackage
uses: game-ci/unity-builder@v2.0-alpha-6
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_LICENSE: ${{ secrets[matrix.license] }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: PackageExporter.Export
versioning: None
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
with:
directory: src/UniTask
- name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
# Store artifacts.
- uses: actions/upload-artifact@v2

View File

@@ -9,10 +9,9 @@ on:
jobs:
run-docfx:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
repository: Cysharp/DocfxTemplate
path: docs/_DocfxTemplate

View File

@@ -6,40 +6,94 @@ on:
tag:
description: "tag: git tag you want create. (sample 1.0.0)"
required: true
dry-run:
description: "dry-run: true will never create relase/nuget."
dry_run:
description: "dry_run: true will never create relase/nuget."
required: true
default: false
type: boolean
default: "false"
env:
GIT_TAG: ${{ github.event.inputs.tag }}
DRY_RUN: ${{ github.event.inputs.dry-run }}
DRY_RUN: ${{ github.event.inputs.dry_run }}
DRY_RUN_BRANCH_PREFIX: "test_release"
DOTNET_SDK_VERISON_3: 3.1.x
jobs:
update-packagejson:
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
with:
file-path: ./src/UniTask/Assets/Plugins/UniTask/package.json
tag: ${{ github.event.inputs.tag }}
dry-run: ${{ fromJson(github.event.inputs.dry-run) }}
runs-on: ubuntu-latest
env:
TARGET_FILE: ./src/UniTask/Assets/Plugins/UniTask/package.json
outputs:
sha: ${{ steps.commit.outputs.sha }}
steps:
- uses: actions/checkout@v2
- name: Output package.json (Before)
run: cat ${{ env.TARGET_FILE}}
- name: Update package.json to version ${{ env.GIT_TAG }}
run: sed -i -e "s/\(\"version\":\) \"\(.*\)\",/\1 \"${{ env.GIT_TAG }}\",/" ${{ env.TARGET_FILE }}
- name: Check update
id: check_update
run: |
cat ${{ env.TARGET_FILE}}
git diff --exit-code || echo "::set-output name=changed::1"
- name: Commit files
id: commit
if: steps.check_update.outputs.changed == '1'
run: |
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "feat: Update package.json to ${{ env.GIT_TAG }}" -a
echo "::set-output name=sha::$(git rev-parse HEAD)"
- name: Check sha
run: echo "SHA ${SHA}"
env:
SHA: ${{ steps.commit.outputs.sha }}
- name: Create Tag
if: steps.check_update.outputs.changed == '1'
run: git tag ${{ env.GIT_TAG }}
- name: Push changes
if: env.DRY_RUN == 'false' && steps.check_update.outputs.changed == '1'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
tags: true
- name: Push changes (dry_run)
if: env.DRY_RUN == 'true' && steps.check_update.outputs.changed == '1'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
tags: false
build-dotnet:
needs: [update-packagejson]
runs-on: ubuntu-latest
timeout-minutes: 10
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
- run: echo ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- uses: actions/setup-dotnet@v1
with:
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
# build and pack
- run: dotnet build -c Release -p:Version=${{ env.GIT_TAG }}
- run: dotnet test -c Release --no-build
- run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ env.GIT_TAG }} -o ./publish
# Store artifacts.
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v1
with:
name: nuget
path: ./publish/
@@ -49,30 +103,38 @@ jobs:
strategy:
matrix:
unity: ["2019.3.9f1"]
include:
- unity: 2019.3.9f1
license: UNITY_LICENSE_2019
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- run: echo ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
# Execute scripts: Export Package
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- name: Build Unity (.unitypacakge)
uses: Cysharp/Actions/.github/actions/unity-builder@main
- name: Export unitypackage
uses: game-ci/unity-builder@v2.0-alpha-6
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_LICENSE: ${{ secrets[matrix.license] }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: PackageExporter.Export
versioning: None
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
with:
directory: src/UniTask
- name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
# Store artifacts.
- uses: actions/upload-artifact@v2
@@ -81,12 +143,18 @@ jobs:
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
create-release:
if: github.event.inputs.dry-run == 'false'
if: github.event.inputs.dry_run == 'false'
needs: [update-packagejson, build-dotnet, build-unity]
runs-on: ubuntu-latest
timeout-minutes: 10
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
# setup dotnet for nuget push
- uses: actions/setup-dotnet@v1
with:
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
# Create Releases
- uses: actions/create-release@v1
id: create_release
@@ -113,8 +181,12 @@ jobs:
asset_content_type: application/octet-stream
cleanup:
if: needs.update-packagejson.outputs.is-branch-created == 'true'
needs: [update-packagejson, build-dotnet, build-unity]
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
with:
branch: ${{ needs.update-packagejson.outputs.branch-name }}
if: github.event.inputs.dry_run == 'true'
needs: [build-dotnet, build-unity]
runs-on: ubuntu-latest
steps:
- name: Delete branch
uses: dawidd6/action-delete-branch@v3
with:
github_token: ${{ github.token }}
branches: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}

View File

@@ -1,10 +0,0 @@
name: Prevent github change
on:
pull_request:
paths:
- ".github/**/*.yaml"
- ".github/**/*.yml"
jobs:
detect:
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main

View File

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

View File

@@ -1,6 +1,6 @@
UniTask
===
[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases) [![Readme_CN](https://img.shields.io/badge/UniTask-%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3-red)](https://github.com/Cysharp/UniTask/blob/master/README_CN.md)
[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases)
Provides an efficient allocation free async/await integration for Unity.
@@ -44,6 +44,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
- [API References](#api-references)
- [UPM Package](#upm-package)
- [Install via git URL](#install-via-git-url)
- [Install via OpenUPM](#install-via-openupm)
- [.NET Core](#net-core)
- [License](#license)
@@ -85,13 +86,8 @@ async UniTask<string> DemoAsync()
await UniTask.Yield();
await UniTask.NextFrame();
// replacement of WaitForEndOfFrame
#if UNITY_2023_1_OR_NEWER
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
await UniTask.WaitForEndOfFrame();
#else
// requires MonoBehaviour(CoroutineRunner))
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
#endif
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask.WaitForFixedUpdate();
@@ -295,7 +291,7 @@ public class MyBehaviour : MonoBehaviour
When cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. When exception(not limited to `OperationCanceledException`) is not handled in async method, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`. The default behaviour of received unhandled exception is to write log as exception. Log level can be changed using `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to use custom behaviour, set an action to `UniTaskScheduler.UnobservedTaskException.`
And also `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.
Andalso `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.
If you want to cancel behaviour in an async UniTask method, throw `OperationCanceledException` manually.
@@ -336,18 +332,6 @@ if (isCanceled)
Note: Only suppress throws if you call directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not suppress throws.
Some features that use Unity's player loop, such as `UniTask.Yield` and `UniTask.Delay` etc, determines CancellationToken state on the player loop.
This means it does not cancel immediately upon `CancellationToken` fired.
If you want to change this behaviour, the cancellation to be immediate, set the `cancelImmediately` flag as an argument.
```csharp
await UniTask.Yield(cancellationToken, cancelImmediately: true);
```
Note: Setting `cancelImmediately` to true and detecting an immediate cancellation is more costly than the default behavior.
This is because it uses `CancellationToken.Register`; it is heavier than checking CancellationToken on the player loop.
Timeout handling
---
Timeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.
@@ -375,7 +359,7 @@ If you want to use timeout with other source of cancellation, use `CancellationT
```csharp
var cancelToken = new CancellationTokenSource();
cancelButton.onClick.AddListener(() =>
cancelButton.onClick.AddListener(()=>
{
cancelToken.Cancel(); // cancel from button click.
});
@@ -512,19 +496,17 @@ 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 to `yield return null` in a 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 to `WaitForFixedUpdate`.
`PlayerLoopTiming.Update` is similar to `yield return null` in a 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 to `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar to `WaitForEndOfFrame` in coroutine.
> `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.
>
> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`.
> `await UniTask.WaitForEndOfFrame()` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, use a coroutine instead.
`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and runs on YieldRunner. It is the most lightweight and fastest.
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and fastest.
`AsyncOperation` is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after being called, the loaded scene's `Start` is called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
In UniTask, await directly uses native timing, while `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
In UniTask, await directly uses native timing, `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
In the stacktrace, you can check where it is running in playerloop.
@@ -676,8 +658,7 @@ By default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField`
There are defined in separated asmdefs like `UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager.
However for DOTween support, after importing from the [DOTWeen assets](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676r) and define the scripting define symbol `UNITASK_DOTWEEN_SUPPORT` to enable it.
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager. However for DOTween support, it is required to import `com.demigiant.dotween` from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or to define `UNITASK_DOTWEEN_SUPPORT` to enable it.
```csharp
// sequential
@@ -700,7 +681,7 @@ Unity 2020.2 supports C# 8.0 so you can use `await foreach`. This is the new Upd
```csharp
// Unity 2020.2, C# 8.0
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(token))
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate(token))
{
Debug.Log("Update() " + Time.frameCount);
}
@@ -710,10 +691,10 @@ In a C# 7.3 environment, you can use the `ForEachAsync` method to work in almost
```csharp
// C# 7.3(Unity 2018.3~)
await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
await UniTaskAsyncEnumerable.EveryUpdate(token).ForEachAsync(_ =>
{
Debug.Log("Update() " + Time.frameCount);
}, token);
});
```
UniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable<T>` or Rx in `IObservable<T>`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.
@@ -736,7 +717,7 @@ Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAs
It's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.
`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`,`Merge` `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
The method with Func as an argument has three additional overloads, `***Await`, `***AwaitWithCancellation`.
@@ -824,13 +805,32 @@ async UniTask TripleClick(CancellationToken token)
}
```
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`. AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`.
```csharp
var trigger = this.GetOnCollisionEnterAsyncHandler();
await trigger.OnCollisionEnterAsync();
await trigger.OnCollisionEnterAsync();
await trigger.OnCollisionEnterAsync();
using Cysharp.Threading.Tasks.Triggers;
async UniTaskVoid MonitorCollision()
{
await gameObject.OnCollisionEnterAsync();
Debug.Log("Collision Enter");
/* do anything */
await gameObject.OnCollisionExitAsync();
Debug.Log("Collision Exit");
}
```
Similar to uGUI event, AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.
```csharp
// use await multiple times, get AsyncTriggerHandler is more efficient.
using(var trigger = this.GetOnCollisionEnterAsyncHandler())
{
await OnCollisionEnterAsync();
await OnCollisionEnterAsync();
await OnCollisionEnterAsync();
}
// every moves.
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
@@ -858,9 +858,9 @@ rp.WithoutCurrent().BindTo(this.textComponent);
await rp.WaitAsync(); // wait until next value set
// also exists ToReadOnlyAsyncReactiveProperty
// also exists ToReadOnlyReactiveProperty
var rp2 = new AsyncReactiveProperty<int>(99);
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyReactiveProperty();
```
A pull-type asynchronous stream does not get the next values until the asynchronous processing in the sequence is complete. This could spill data from push-type events such as buttons.
@@ -966,9 +966,9 @@ UniTask's own unit tests are written using Unity Test Runner and [Cysharp/Runtim
ThreadPool limitation
---
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run`(`Task.Run` equivalent) and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run` and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
`UniTask.Run` is now deprecated. You can use `UniTask.RunOnThreadPool` instead. And also consider whether you can use `UniTask.Create` or `UniTask.Void`.
`UniTask.Run` will be deprecated in the future (marked with an Obsolete) and only `RunOnThreadPool` will be used. If you use `UniTask.Run`, consider whether you can use `UniTask.Create` or `UniTask.Void`.
IEnumerator.ToUniTask limitation
---
@@ -1023,7 +1023,7 @@ Use UniTask type.
| `IAsyncDisposable` | `IUniTaskAsyncDisposable` |
| `Task.Delay` | `UniTask.Delay` |
| `Task.Yield` | `UniTask.Yield` |
| `Task.Run` | `UniTask.RunOnThreadPool` |
| `Task.Run` | `UniTask.Run` |
| `Task.WhenAll` | `UniTask.WhenAll` |
| `Task.WhenAny` | `UniTask.WhenAny` |
| `Task.CompletedTask` | `UniTask.CompletedTask` |
@@ -1091,6 +1091,13 @@ or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/
If you want to set a target version, UniTask uses the `*.*.*` release tag so you can specify a version like `#2.1.0`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0`.
### Install via OpenUPM
The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
```
openupm add com.cysharp.unitask
```
.NET Core
---
@@ -1100,7 +1107,7 @@ For .NET Core, use NuGet.
UniTask of .NET Core version is a subset of Unity UniTask with PlayerLoop dependent methods removed.
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AsyncLocal` also does not work because it ignores ExecutionContext.
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AysncLocal` also does not work because it ignores ExecutionContext.
If you use UniTask internally, but provide ValueTask as an external API, you can write it like the following(Inspired by [PooledAwait](https://github.com/mgravell/PooledAwait)).

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,13 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31606.5
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCore", "src\UniTask.NetCore\UniTask.NetCore.csproj", "{16EE20D0-7FB1-483A-8467-A5EEDBF1F5BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.Analyzer", "src\UniTask.Analyzer\UniTask.Analyzer.csproj", "{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -29,10 +27,6 @@ Global
{3915E72E-33E0-4A14-A6D8-872702200E58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.Build.0 = Release|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,8 +0,0 @@
{
"profiles": {
"UniTask.Analyzer": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\UniTask.NetCoreSandbox\\UniTask.NetCoreSandbox.csproj"
}
}
}

View File

@@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>library</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<IsRoslynComponent>true</IsRoslynComponent>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackBuildOutputs</TargetsForTfmSpecificContentInPackage>
<IncludeBuildOutput>false</IncludeBuildOutput>
<IncludeSymbols>false</IncludeSymbols>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
</ItemGroup>
<Target Name="PackBuildOutputs" DependsOnTargets="SatelliteDllsProjectOutputGroup;DebugSymbolsProjectOutputGroup">
<ItemGroup>
<TfmSpecificPackageFile Include="$(TargetDir)\*.dll" PackagePath="analyzers\dotnet\cs" />
<TfmSpecificPackageFile Include="@(SatelliteDllsProjectOutputGroupOutput->'%(FinalOutputPath)')" PackagePath="analyzers\dotnet\cs\%(SatelliteDllsProjectOutputGroupOutput.Culture)\" />
</ItemGroup>
</Target>
</Project>

View File

@@ -1,54 +0,0 @@
#pragma warning disable RS2008
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using System.Collections.Immutable;
using System.Threading;
namespace UniTask.Analyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class UniTaskAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
id: "UNITASK001",
title: "UniTaskAnalyzer001: Must pass CancellationToken",
messageFormat: "Must pass CancellationToken",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "Pass CancellationToken or CancellationToken.None.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation);
}
private static void AnalyzeOperation(OperationAnalysisContext context)
{
var token = context.Compilation.GetTypeByMetadataName(typeof(CancellationToken).FullName);
if (token == null) return;
if (context.Operation is IInvocationOperation invocation)
{
foreach (var arg in invocation.Arguments)
{
if (arg.ArgumentKind == ArgumentKind.DefaultValue)
{
if (SymbolEqualityComparer.Default.Equals(arg.Parameter.Type, token))
{
var diagnostic = Diagnostic.Create(Rule, arg.Syntax.GetLocation());
context.ReportDiagnostic(diagnostic);
}
}
}
}
}
}
}

View File

@@ -1,5 +1,4 @@
#if !UNITY_2018_3_OR_NEWER || UNITY_2021_2_OR_NEWER
#pragma warning disable 0649
#pragma warning disable 0649
using System;
using System.Threading.Tasks;
@@ -96,4 +95,3 @@ namespace Cysharp.Threading.Tasks
#endif
}
}
#endif

View File

@@ -1,12 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net7.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0</TargetFrameworks>
<AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<!-- NuGet Packaging -->
<Id>UniTask</Id>
@@ -23,7 +21,6 @@
<PackageIcon>Icon.png</PackageIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>opensource.snk</AssemblyOriginatorKeyFile>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,258 @@
using BenchmarkDotNet.Attributes;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Cysharp.Threading.Tasks;
using PooledAwait;
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks.CompilerServices;
using System.Collections.Concurrent;
[Config(typeof(BenchmarkConfig))]
public class AllocationCheck
{
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
// iterations, so that we're only really measuring the inner loop
private const int InnerOps = 1000;
[Benchmark(OperationsPerInvoke = InnerOps)]
public async Task ViaUniTask()
{
for (int i = 0; i < InnerOps; i++)
{
var a = Core();
var b = Core();
var c = Core();
await a;
await b;
await c;
}
static async UniTask Core()
{
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
}
}
[Benchmark(OperationsPerInvoke = InnerOps)]
public async Task<int> ViaUniTaskT()
{
var sum = 0;
for (int i = 0; i < InnerOps; i++)
{
var a = Core();
var b = Core();
var c = Core();
sum += await a;
sum += await b;
sum += await c;
}
return sum;
static async UniTask<int> Core()
{
var a = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
var b = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
var c = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
return 10;
}
}
//[Benchmark(OperationsPerInvoke = InnerOps)]
//[Benchmark]
public void ViaUniTaskVoid()
{
for (int i = 0; i < InnerOps; i++)
{
Core().Forget();
Core().Forget();
Core().Forget();
}
static async UniTaskVoid Core()
{
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
}
}
struct Foo : IAsyncStateMachine
{
public AsyncUniTaskVoidMethodBuilder builder;
public TestAwaiter awaiter;
public TestAwaiter awaiterawaiter;
public int state;
public void MoveNext()
{
switch (state)
{
case -1:
awaiterawaiter = awaiter.GetAwaiter();
if (awaiterawaiter.IsCompleted)
{
goto case 0;
}
else
{
state = 0;
builder.AwaitUnsafeOnCompleted(ref awaiterawaiter, ref this);
return;
}
case 0:
default:
goto END;
}
END:
builder.SetResult();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}
}
public class TaskTestException : Exception
{
}
public struct TestAwaiter : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
public TestAwaiter(bool isCompleted, UniTaskStatus status)
{
this.isCompleted = isCompleted;
this.status = status;
}
public TestAwaiter GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public void GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
break;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
}
public struct TestAwaiter<T> : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
readonly T value;
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
{
this.isCompleted = isCompleted;
this.status = status;
this.value = value;
}
public TestAwaiter<T> GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public T GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
return value;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
}
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
{
public static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
public static void CreatePoolItems(int count)
{
for (int i = 0; i < count; i++)
{
pool.Enqueue(new ThreadPoolWorkItem());
}
}
Action continuation;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ThreadPoolWorkItem Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new ThreadPoolWorkItem();
}
item.continuation = continuation;
return item;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute()
{
var call = continuation;
continuation = null;
pool.Enqueue(this);
call.Invoke();
}
}

View File

@@ -0,0 +1,283 @@
using BenchmarkDotNet.Attributes;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Cysharp.Threading.Tasks;
using PooledAwait;
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks.CompilerServices;
//class Program
//{
// static void Main(string[] args)
// {
// var switcher = new BenchmarkSwitcher(new[]
// {
// typeof(StandardBenchmark)
// });
//#if DEBUG
// var b = new StandardBenchmark();
//#else
// switcher.Run(args);
//#endif
// }
//}
public class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
AddDiagnoser(MemoryDiagnoser.Default);
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1)/*.RunOncePerIteration()*/);
}
}
// borrowed from PooledAwait
[Config(typeof(BenchmarkConfig))]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
[CategoriesColumn]
public class ComparisonBenchmarks
{
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
// iterations, so that we're only really measuring the inner loop
private const int InnerOps = 1000;
public bool ConfigureAwait { get; set; } = false;
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("Task<T>")]
public async Task<int> ViaTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async Task<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("Task")]
public async Task ViaTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async Task Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("ValueTask<T>")]
public async Task<int> ViaValueTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async ValueTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("ValueTask")]
public async Task ViaValueTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async ValueTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("ValueTask<T>")]
public async Task<int> ViaPooledValueTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async PooledValueTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("ValueTask")]
public async Task ViaPooledValueTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async PooledValueTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("Task<T>")]
public async Task<int> ViaPooledTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async PooledTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("Task")]
public async Task ViaPooledTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async PooledTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
// ---
//[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskVoid")]
//[BenchmarkCategory("UniTask")]
//public async Task ViaUniTaskVoid()
//{
// for (int i = 0; i < InnerOps; i++)
// {
// await Inner();
// }
// static async UniTaskVoid Inner()
// {
// await UniTask.Yield();
// await UniTask.Yield();
// }
//}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTask")]
[BenchmarkCategory("UniTask")]
public async Task ViaUniTask()
{
for (int i = 0; i < InnerOps; i++)
{
await Inner();
}
static async UniTask Inner()
{
await UniTask.Yield();
await UniTask.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskT")]
[BenchmarkCategory("UniTask")]
public async Task<int> ViaUniTaskT()
{
var sum = 0;
for (int i = 0; i < InnerOps; i++)
{
sum += await Inner(1, 2);
}
return sum;
static async UniTask<int> Inner(int x, int y)
{
int i = x;
await UniTask.Yield();
i *= y;
await UniTask.Yield();
return 5 * i;
}
}
}
public struct MyAwaiter : ICriticalNotifyCompletion
{
public MyAwaiter GetAwaiter() => this;
public bool IsCompleted => false;
public void GetResult()
{
}
public void OnCompleted(Action continuation)
{
continuation();
}
public void UnsafeOnCompleted(Action continuation)
{
continuation();
}
}
public struct MyTestStateMachine : IAsyncStateMachine
{
public void MoveNext()
{
//throw new NotImplementedException();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
//throw new NotImplementedException();
}
}

View File

@@ -17,34 +17,499 @@ using System.Reactive.Concurrency;
namespace NetCoreSandbox
{
public class Program
public class MySyncContext : SynchronizationContext
{
static async Task Main(string[] args)
public MySyncContext()
{
var cts = new CancellationTokenSource();
// OK.
await FooAsync(10, cts.Token);
// NG(Compiler Error)
// await FooAsync(10);
}
static async UniTask FooAsync(int x, CancellationToken cancellationToken = default)
public override void Post(SendOrPostCallback d, object state)
{
await UniTask.Yield();
Console.WriteLine("Called SyncContext Post!");
base.Post(d, state);
}
}
public class Text
{
public string text { get; set; }
}
public class ZeroAllocAsyncAwaitInDotNetCore
{
public ValueTask<int> NanikaAsync(int x, int y)
{
return Core(this, x, y);
static async UniTask<int> Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
{
// nanika suru...
await Task.Delay(TimeSpan.FromSeconds(x + y));
return 10;
}
}
}
public class TaskTestException : Exception
{
}
class Foo
{
public async UniTask MethodFooAsync()
{
await MethodBarAsync();
}
private async UniTask MethodBarAsync()
{
Throw();
}
private void Throw()
{
throw new Exception();
}
}
public struct TestAwaiter : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
public TestAwaiter(bool isCompleted, UniTaskStatus status)
{
this.isCompleted = isCompleted;
this.status = status;
}
public TestAwaiter GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public void GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
break;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
}
}
public struct TestAwaiter<T> : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
readonly T value;
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
{
this.isCompleted = isCompleted;
this.status = status;
this.value = value;
}
public TestAwaiter<T> GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public T GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
return value;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
}
}
public static partial class UnityUIComponentExtensions
{
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
{
AAAACORECORE(source, text).Forget();
async UniTaskVoid AAAACORECORE(IUniTaskAsyncEnumerable<string> source2, Text text2)
{
var e = source2.GetAsyncEnumerator();
try
{
while (await e.MoveNextAsync())
{
text2.text = e.Current;
// action(e.Current);
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
}
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
//{
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
//}
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
//{
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
//}
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
//{
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
//}
}
class Program
{
static string FlattenGenArgs(Type type)
{
if (type.IsGenericType)
{
var t = string.Join(", ", type.GetGenericArguments().Select(x => FlattenGenArgs(x)));
return Regex.Replace(type.Name, "`.+", "") + "<" + t + ">";
}
//x.ReturnType.GetGenericArguments()
else
{
return type.Name;
}
}
static async IAsyncEnumerable<int> FooAsync([EnumeratorCancellation]CancellationToken cancellationToken = default)
{
yield return 1;
await Task.Delay(10, cancellationToken);
}
public class MyDisposable : IDisposable
{
public void Dispose()
{
}
}
static void Test()
{
var disp = new MyDisposable();
using var _ = new MyDisposable();
Console.WriteLine("tako");
}
static async UniTask FooBarAsync()
{
await using (UniTask.ReturnToCurrentSynchronizationContext())
{
await UniTask.SwitchToThreadPool();
}
}
static async UniTask Aaa()
{
await FooBarAsync();
Console.WriteLine("FooBarAsync End");
}
static async UniTask WhereSelect()
{
await foreach (var item in UniTaskAsyncEnumerable.Range(1, 10)
.SelectAwait(async x =>
{
await UniTask.Yield();
return x;
})
.Where(x => x % 2 == 0))
{
Console.WriteLine(item);
}
}
static async Task Main(string[] args)
{
#if !DEBUG
//await new AllocationCheck().ViaUniTaskVoid();
//Console.ReadLine();
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
//await new ComparisonBenchmarks().ViaUniTaskT();
return;
#endif
var e = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Start {i}");
await writer.YieldAsync(i);
Console.WriteLine($"End {i}");
}
});
var ee = e.GetAsyncEnumerator();
while (await ee.MoveNextAsync())
{
Console.WriteLine("ForEach " + ee.Current);
}
}
static async UniTask YieldCore()
{
await UniTask.Yield();
}
#pragma warning disable CS1998
static async UniTask<int> AsyncTest()
{
// empty
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(true, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
return 10;
}
#pragma warning restore CS1998
void Foo()
{
// AsyncEnumerable.Range(1,10).Do(
// AsyncEnumerable.t
var sb = new StringBuilder();
sb.AppendLine(@"using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
");
var chako = typeof(AsyncEnumerable).GetMethods()
.OrderBy(x => x.Name)
.Select(x =>
{
var ret = FlattenGenArgs(x.ReturnType);
var generics = string.Join(", ", x.GetGenericArguments().Select(x => x.Name));
if (x.GetParameters().Length == 0) return "";
var self = x.GetParameters().First();
if (x.GetCustomAttributes(typeof(ExtensionAttribute), true).Length == 0)
{
return "";
}
var arg1Type = FlattenGenArgs(x.GetParameters().First().ParameterType);
var others = string.Join(", ", x.GetParameters().Skip(1).Select(y => FlattenGenArgs(y.ParameterType) + " " + y.Name));
if (!string.IsNullOrEmpty(others))
{
others = ", " + others;
}
var template = $"public static {ret} {x.Name}<{generics}>(this {arg1Type} {self.Name}{others})";
return template.Replace("ValueTask", "UniTask").Replace("IAsyncEnumerable", "IUniTaskAsyncEnumerable").Replace("<>", "");
})
.Where(x => x != "")
.Select(x => x + "\r\n{\r\n throw new NotImplementedException();\r\n}")
.ToArray();
var huga = string.Join("\r\n\r\n", chako);
foreach (var item in typeof(AsyncEnumerable).GetMethods().Select(x => x.Name).Distinct())
{
if (item.EndsWith("AwaitAsync") || item.EndsWith("AwaitWithCancellationAsync") || item.EndsWith("WithCancellation"))
{
continue;
}
var item2 = item.Replace("Async", "");
item2 = item2.Replace("Await", "");
var format = @"
internal sealed class {0}
{{
}}
";
sb.Append(string.Format(format, item2));
}
sb.Append("}");
Console.WriteLine(sb.ToString());
}
public static async IAsyncEnumerable<int> AsyncGen()
{
await UniTask.SwitchToThreadPool();
yield return 10;
await UniTask.SwitchToThreadPool();
yield return 100;
}
}
class MyEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new MyEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
class MyEnumerator : IEnumerator<int>
{
public int Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose()
{
Console.WriteLine("Called Dispose");
}
public bool MoveNext()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
}
public class MyClass<T>
{
public CustomAsyncEnumerator<T> GetAsyncEnumerator()
{
//IAsyncEnumerable
return new CustomAsyncEnumerator<T>();
}
}
public struct CustomAsyncEnumerator<T>
{
int count;
public T Current
{
get
{
return default;
}
}
public UniTask<bool> MoveNextAsync()
{
if (count++ == 3)
{
return UniTask.FromResult(false);
//return false;
}
return UniTask.FromResult(true);
}
public UniTask DisposeAsync()
{
return default;
}
}
}

View File

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

View File

@@ -2,9 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>NetCoreSandbox</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
@@ -16,12 +15,6 @@
<ItemGroup>
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -159,30 +159,6 @@ namespace NetCoreTests.Linq
list.Should().Equal(100, 200, 300, 400);
}
[Fact]
public async Task AwaitForeachBreak()
{
var finallyCalled = false;
var enumerable = UniTaskAsyncEnumerable.Create<int>(async (writer, _) =>
{
try
{
await writer.YieldAsync(1);
}
finally
{
finallyCalled = true;
}
});
await foreach (var x in enumerable)
{
x.Should().Be(1);
break;
}
finallyCalled.Should().BeTrue();
}
async IAsyncEnumerable<int> Range(int from, int count)
{
for (int i = 0; i < count; i++)

View File

@@ -1,137 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using Xunit;
namespace NetCoreTests.Linq
{
public class MergeTest
{
[Fact]
public async Task TwoSource()
{
var semaphore = new SemaphoreSlim(1, 1);
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("A1");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("A2");
semaphore.Release();
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("B1");
await writer.YieldAsync("B2");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("B3");
semaphore.Release();
});
var result = await a.Merge(b).ToArrayAsync();
result.Should().Equal("A1", "B1", "B2", "A2", "B3");
}
[Fact]
public async Task ThreeSource()
{
var semaphore = new SemaphoreSlim(0, 1);
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("A1");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("A2");
semaphore.Release();
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("B1");
await writer.YieldAsync("B2");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("B3");
semaphore.Release();
});
var c = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await writer.YieldAsync("C1");
semaphore.Release();
});
var result = await a.Merge(b, c).ToArrayAsync();
result.Should().Equal("C1", "A1", "B1", "B2", "A2", "B3");
}
[Fact]
public async Task Throw()
{
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("A1");
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
throw new UniTaskTestException();
});
var enumerator = a.Merge(b).GetAsyncEnumerator();
(await enumerator.MoveNextAsync()).Should().Be(true);
enumerator.Current.Should().Be("A1");
await Assert.ThrowsAsync<UniTaskTestException>(async () => await enumerator.MoveNextAsync());
}
[Fact]
public async Task Cancel()
{
var cts = new CancellationTokenSource();
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("A1");
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("B1");
});
var enumerator = a.Merge(b).GetAsyncEnumerator(cts.Token);
(await enumerator.MoveNextAsync()).Should().Be(true);
enumerator.Current.Should().Be("A1");
cts.Cancel();
await Assert.ThrowsAsync<OperationCanceledException>(async () => await enumerator.MoveNextAsync());
}
}
}

View File

@@ -1,43 +0,0 @@
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class TaskExtensionsTest
{
[Fact]
public async Task PropagateException()
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await ThrowAsync().AsUniTask();
});
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await ThrowOrValueAsync().AsUniTask();
});
}
[Fact]
public async Task PropagateExceptionWhenAll()
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await Task.WhenAll(ThrowAsync(), ThrowAsync()).AsUniTask();
});
}
async Task ThrowAsync()
{
throw new InvalidOperationException();
}
async Task<int> ThrowOrValueAsync()
{
throw new InvalidOperationException();
}
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>

View File

@@ -1,80 +0,0 @@
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using FluentAssertions;
using NetCoreTests.Linq;
using Xunit;
namespace NetCoreTests
{
public class AutoResetUniTaskCompletionSourceTest
{
[Fact]
public async Task SetResultAfterReturn()
{
var source1 = AutoResetUniTaskCompletionSource.Create();
source1.TrySetResult();
await source1.Task;
source1.TrySetResult().Should().BeFalse();
var source2 = AutoResetUniTaskCompletionSource.Create();
source2.TrySetResult();
await source2.Task;
source2.TrySetResult().Should().BeFalse();
}
[Fact]
public async Task SetCancelAfterReturn()
{
var source = AutoResetUniTaskCompletionSource.Create();
source.TrySetResult();
await source.Task;
source.TrySetCanceled().Should().BeFalse();
}
[Fact]
public async Task SetExceptionAfterReturn()
{
var source = AutoResetUniTaskCompletionSource.Create();
source.TrySetResult();
await source.Task;
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
}
[Fact]
public async Task SetResultWithValueAfterReturn()
{
var source1 = AutoResetUniTaskCompletionSource<int>.Create();
source1.TrySetResult(100);
(await source1.Task).Should().Be(100);
source1.TrySetResult(100).Should().BeFalse();
var source2 = AutoResetUniTaskCompletionSource.Create();
source2.TrySetResult();
await source2.Task;
source2.TrySetResult().Should().BeFalse();
}
[Fact]
public async Task SetCancelWithValueAfterReturn()
{
var source = AutoResetUniTaskCompletionSource<int>.Create();
source.TrySetResult(100);
(await source.Task).Should().Be(100);
source.TrySetCanceled().Should().BeFalse();
}
[Fact]
public async Task SetExceptionWithValueAfterReturn()
{
var source = AutoResetUniTaskCompletionSource<int>.Create();
source.TrySetResult(100);
(await source.Task).Should().Be(100);
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
}
}
}

View File

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

View File

@@ -25,12 +25,7 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(handle, cancellationToken: cancellationToken);
}
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
@@ -49,7 +44,7 @@ namespace Cysharp.Threading.Tasks
return UniTask.CompletedTask;
}
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
}
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
@@ -111,7 +106,6 @@ namespace Cysharp.Threading.Tasks
readonly Action<AsyncOperationHandle> continuationAction;
AsyncOperationHandle handle;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
IProgress<float> progress;
bool completed;
@@ -122,7 +116,7 @@ namespace Cysharp.Threading.Tasks
continuationAction = Continuation;
}
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -138,15 +132,6 @@ namespace Cysharp.Threading.Tasks
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncOperationHandleConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -234,7 +219,6 @@ namespace Cysharp.Threading.Tasks
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -253,12 +237,7 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(handle, cancellationToken: cancellationToken);
}
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
@@ -276,7 +255,7 @@ namespace Cysharp.Threading.Tasks
return UniTask.FromResult(handle.Result);
}
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
}
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
@@ -293,7 +272,6 @@ namespace Cysharp.Threading.Tasks
readonly Action<AsyncOperationHandle<T>> continuationAction;
AsyncOperationHandle<T> handle;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
IProgress<float> progress;
bool completed;
@@ -304,7 +282,7 @@ namespace Cysharp.Threading.Tasks
continuationAction = Continuation;
}
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -320,15 +298,6 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
result.completed = false;
result.progress = progress;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncOperationHandleConfiguredSource<T>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -421,7 +390,6 @@ namespace Cysharp.Threading.Tasks
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}

View File

@@ -16,12 +16,7 @@
"name": "com.unity.addressables",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
},
{
"name": "com.unity.addressables.cn",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
}
],
"noEngineReferences": false
}
}

View File

@@ -16,14 +16,14 @@ namespace Cysharp.Threading.Tasks
Kill,
KillWithCompleteCallback,
Complete,
CompleteWithSequenceCallback,
CompleteWithSeqeunceCallback,
CancelAwait,
// AndCancelAwait
KillAndCancelAwait,
KillWithCompleteCallbackAndCancelAwait,
CompleteAndCancelAwait,
CompleteWithSequenceCallbackAndCancelAwait
CompleteWithSeqeunceCallbackAndCancelAwait
}
public static class DOTweenAsyncExtensions
@@ -143,21 +143,24 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
}
static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onCompleteCallbackDelegate;
readonly TweenCallback onUpdateDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationRegistration;
CallbackType callbackType;
bool canceled;
TweenCallback originalCompleteAction;
TweenCallback originalUpdateAction;
UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource()
{
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
onUpdateDelegate = OnUpdate;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
@@ -177,87 +180,41 @@ namespace Cysharp.Threading.Tasks
result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken;
result.callbackType = callbackType;
result.originalUpdateAction = tween.onUpdate;
result.canceled = false;
if (result.originalUpdateAction == result.onUpdateDelegate)
{
result.originalUpdateAction = null;
}
tween.onUpdate = result.onUpdateDelegate;
switch (callbackType)
{
case CallbackType.Kill:
result.originalCompleteAction = tween.onKill;
tween.onKill = result.onCompleteCallbackDelegate;
break;
case CallbackType.Complete:
result.originalCompleteAction = tween.onComplete;
tween.onComplete = result.onCompleteCallbackDelegate;
break;
case CallbackType.Pause:
result.originalCompleteAction = tween.onPause;
tween.onPause = result.onCompleteCallbackDelegate;
break;
case CallbackType.Play:
result.originalCompleteAction = tween.onPlay;
tween.onPlay = result.onCompleteCallbackDelegate;
break;
case CallbackType.Rewind:
result.originalCompleteAction = tween.onRewind;
tween.onRewind = result.onCompleteCallbackDelegate;
break;
case CallbackType.StepComplete:
result.originalCompleteAction = tween.onStepComplete;
tween.onStepComplete = result.onCompleteCallbackDelegate;
break;
default:
break;
}
if (result.originalCompleteAction == result.onCompleteCallbackDelegate)
{
result.originalCompleteAction = null;
}
if (cancellationToken.CanBeCanceled)
{
result.cancellationRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(x =>
{
var source = (TweenConfiguredSource)x;
switch (source.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
source.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
source.canceled = true;
source.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
source.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
source.canceled = true;
source.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
source.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
source.canceled = true;
source.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallback:
source.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
source.canceled = true;
source.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
source.RestoreOriginalCallback();
source.core.TrySetCanceled(source.cancellationToken);
break;
}
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
@@ -271,7 +228,7 @@ namespace Cysharp.Threading.Tasks
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
{
canceled = true;
@@ -283,11 +240,81 @@ namespace Cysharp.Threading.Tasks
}
else
{
originalCompleteAction?.Invoke();
core.TrySetResult(AsyncUnit.Default);
}
}
void OnUpdate()
{
originalUpdateAction?.Invoke();
if (!cancellationToken.IsCancellationRequested)
{
return;
}
switch (this.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
this.canceled = true;
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
this.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
this.canceled = true;
this.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
this.canceled = true;
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
this.canceled = true;
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
// replace to empty(avoid callback after Canceled(instance is returned to pool.)
switch (callbackType)
{
case CallbackType.Kill:
tween.onKill = EmptyTweenCallback;
break;
case CallbackType.Complete:
tween.onComplete = EmptyTweenCallback;
break;
case CallbackType.Pause:
tween.onPause = EmptyTweenCallback;
break;
case CallbackType.Play:
tween.onPlay = EmptyTweenCallback;
break;
case CallbackType.Rewind:
tween.onRewind = EmptyTweenCallback;
break;
case CallbackType.StepComplete:
tween.onStepComplete = EmptyTweenCallback;
break;
default:
break;
}
this.core.TrySetCanceled(this.cancellationToken);
break;
}
}
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
{
@@ -312,10 +339,10 @@ namespace Cysharp.Threading.Tasks
case TweenCancelBehaviour.CompleteAndCancelAwait:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallback:
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
@@ -354,41 +381,36 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationRegistration.Dispose();
tween.onUpdate = originalUpdateAction;
RestoreOriginalCallback();
tween = default;
cancellationToken = default;
originalCompleteAction = default;
return pool.TryPush(this);
}
void RestoreOriginalCallback()
{
switch (callbackType)
{
case CallbackType.Kill:
tween.onKill = originalCompleteAction;
tween.onKill = null;
break;
case CallbackType.Complete:
tween.onComplete = originalCompleteAction;
tween.onComplete = null;
break;
case CallbackType.Pause:
tween.onPause = originalCompleteAction;
tween.onPause = null;
break;
case CallbackType.Play:
tween.onPlay = originalCompleteAction;
tween.onPlay = null;
break;
case CallbackType.Rewind:
tween.onRewind = originalCompleteAction;
tween.onRewind = null;
break;
case CallbackType.StepComplete:
tween.onStepComplete = originalCompleteAction;
tween.onStepComplete = null;
break;
default:
break;
}
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 || UNITY_2021_2_OR_NEWER) && !NETSTANDARD2_0
#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 || UNITY_2021_2_OR_NEWER) && !NETSTANDARD2_0
#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 || UNITY_2021_2_OR_NEWER) && !NETSTANDARD2_0
#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 || UNITY_2021_2_OR_NEWER) && !NETSTANDARD2_0
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
new public UniTaskStatus GetStatus(short token)
{

View File

@@ -148,7 +148,7 @@ namespace Cysharp.Threading.Tasks.Internal
foreach (var candidateMethod in methods)
{
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(false);
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>();
if (attributes == null)
{
continue;

View File

@@ -39,7 +39,7 @@ namespace Cysharp.Threading.Tasks.Internal
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowArgumentException(string message)
public static void ThrowArgumentException<T>(string message)
{
throw new ArgumentException(message);
}

View File

@@ -52,7 +52,6 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
writer.Dispose();
return default;
}
@@ -128,7 +127,7 @@ namespace Cysharp.Threading.Tasks.Linq
}
}
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>, IDisposable
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
{
readonly _Create enumerator;
@@ -138,15 +137,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
this.enumerator = enumerator;
}
public void Dispose()
{
var status = core.GetStatus(core.Version);
if (status == UniTaskStatus.Pending)
{
core.TrySetCanceled();
}
}
public void GetResult(short token)
{

View File

@@ -1,232 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
return new Merge<T>(new [] { first, second });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second, IUniTaskAsyncEnumerable<T> third)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(third, nameof(third));
return new Merge<T>(new[] { first, second, third });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
{
return new Merge<T>(sources.ToArray());
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(params IUniTaskAsyncEnumerable<T>[] sources)
{
return new Merge<T>(sources);
}
}
internal sealed class Merge<T> : IUniTaskAsyncEnumerable<T>
{
readonly IUniTaskAsyncEnumerable<T>[] sources;
public Merge(IUniTaskAsyncEnumerable<T>[] sources)
{
if (sources.Length <= 0)
{
Error.ThrowArgumentException("No source async enumerable to merge");
}
this.sources = sources;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new _Merge(sources, cancellationToken);
enum MergeSourceState
{
Pending,
Running,
Completed,
}
sealed class _Merge : MoveNextSource, IUniTaskAsyncEnumerator<T>
{
static readonly Action<object> GetResultAtAction = GetResultAt;
readonly int length;
readonly IUniTaskAsyncEnumerator<T>[] enumerators;
readonly MergeSourceState[] states;
readonly Queue<(T, Exception, bool)> queuedResult = new Queue<(T, Exception, bool)>();
readonly CancellationToken cancellationToken;
int moveNextCompleted;
public T Current { get; private set; }
public _Merge(IUniTaskAsyncEnumerable<T>[] sources, CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
length = sources.Length;
states = ArrayPool<MergeSourceState>.Shared.Rent(length);
enumerators = ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Rent(length);
for (var i = 0; i < length; i++)
{
enumerators[i] = sources[i].GetAsyncEnumerator(cancellationToken);
states[i] = (int)MergeSourceState.Pending;;
}
}
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
completionSource.Reset();
Interlocked.Exchange(ref moveNextCompleted, 0);
if (HasQueuedResult() && Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
(T, Exception, bool) value;
lock (states)
{
value = queuedResult.Dequeue();
}
var resultValue = value.Item1;
var exception = value.Item2;
var hasNext = value.Item3;
if (exception != null)
{
completionSource.TrySetException(exception);
}
else
{
Current = resultValue;
completionSource.TrySetResult(hasNext);
}
return new UniTask<bool>(this, completionSource.Version);
}
for (var i = 0; i < length; i++)
{
lock (states)
{
if (states[i] == MergeSourceState.Pending)
{
states[i] = MergeSourceState.Running;
}
else
{
continue;
}
}
var awaiter = enumerators[i].MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
GetResultAt(i, awaiter);
}
else
{
awaiter.SourceOnCompleted(GetResultAtAction, StateTuple.Create(this, i, awaiter));
}
}
return new UniTask<bool>(this, completionSource.Version);
}
public async UniTask DisposeAsync()
{
for (var i = 0; i < length; i++)
{
await enumerators[i].DisposeAsync();
}
ArrayPool<MergeSourceState>.Shared.Return(states, true);
ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Return(enumerators, true);
}
static void GetResultAt(object state)
{
using (var tuple = (StateTuple<_Merge, int, UniTask<bool>.Awaiter>)state)
{
tuple.Item1.GetResultAt(tuple.Item2, tuple.Item3);
}
}
void GetResultAt(int index, UniTask<bool>.Awaiter awaiter)
{
bool hasNext;
bool completedAll;
try
{
hasNext = awaiter.GetResult();
}
catch (Exception ex)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
completionSource.TrySetException(ex);
}
else
{
lock (states)
{
queuedResult.Enqueue((default, ex, default));
}
}
return;
}
lock (states)
{
states[index] = hasNext ? MergeSourceState.Pending : MergeSourceState.Completed;
completedAll = !hasNext && IsCompletedAll();
}
if (hasNext || completedAll)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
Current = enumerators[index].Current;
completionSource.TrySetResult(!completedAll);
}
else
{
lock (states)
{
queuedResult.Enqueue((enumerators[index].Current, null, !completedAll));
}
}
}
}
bool HasQueuedResult()
{
lock (states)
{
return queuedResult.Count > 0;
}
}
bool IsCompletedAll()
{
lock (states)
{
for (var i = 0; i < length; i++)
{
if (states[i] != MergeSourceState.Completed)
{
return false;
}
}
}
return true;
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ca56812f160c45d0bacb4339819edf1a
timeCreated: 1694133666

View File

@@ -4,50 +4,38 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
{
return new EveryUpdate(updateTiming, cancelImmediately);
return new EveryUpdate(updateTiming);
}
}
internal class EveryUpdate : IUniTaskAsyncEnumerable<AsyncUnit>
{
readonly PlayerLoopTiming updateTiming;
readonly bool cancelImmediately;
public EveryUpdate(PlayerLoopTiming updateTiming, bool cancelImmediately)
public EveryUpdate(PlayerLoopTiming updateTiming)
{
this.updateTiming = updateTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryUpdate(updateTiming, cancellationToken, cancelImmediately);
return new _EveryUpdate(updateTiming, cancellationToken);
}
class _EveryUpdate : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{
readonly PlayerLoopTiming updateTiming;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
CancellationToken cancellationToken;
bool disposed;
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
{
this.updateTiming = updateTiming;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryUpdate)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
}
@@ -56,14 +44,10 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
if (disposed) return CompletedTasks.False;
completionSource.Reset();
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -71,7 +55,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -80,13 +63,7 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (disposed)
if (disposed || cancellationToken.IsCancellationRequested)
{
completionSource.TrySetResult(false);
return false;

View File

@@ -7,7 +7,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null)
where TTarget : class
{
var unityObject = target as UnityEngine.Object;
@@ -15,11 +15,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (isUnityObject)
{
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
}
else
{
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
}
}
}
@@ -30,20 +30,18 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
{
this.target = target;
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
}
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@@ -52,14 +50,13 @@ namespace Cysharp.Threading.Tasks.Linq
readonly UnityEngine.Object targetAsUnityObject;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
CancellationToken cancellationToken;
bool first;
TProperty currentValue;
bool disposed;
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
{
this.target = target;
this.targetAsUnityObject = target as UnityEngine.Object;
@@ -67,16 +64,6 @@ namespace Cysharp.Threading.Tasks.Linq
this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken;
this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this);
}
@@ -85,15 +72,8 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
if (disposed) return CompletedTasks.False;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return new UniTask<bool>(this, completionSource.Version);
}
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
if (first)
{
@@ -106,6 +86,7 @@ namespace Cysharp.Threading.Tasks.Linq
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -113,7 +94,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -122,18 +102,13 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || targetAsUnityObject == null)
if (disposed || cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
{
completionSource.TrySetResult(false);
DisposeAsync().Forget();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
TProperty nextValue = default(TProperty);
try
{
@@ -164,20 +139,18 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
{
this.target = new WeakReference<TTarget>(target, false);
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
}
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@@ -185,30 +158,19 @@ namespace Cysharp.Threading.Tasks.Linq
readonly WeakReference<TTarget> target;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
CancellationToken cancellationToken;
bool first;
TProperty currentValue;
bool disposed;
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
{
this.target = target;
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken;
this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this);
}
@@ -217,16 +179,8 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
if (disposed) return CompletedTasks.False;
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return new UniTask<bool>(this, completionSource.Version);
}
if (first)
{
first = false;
@@ -238,6 +192,7 @@ namespace Cysharp.Threading.Tasks.Linq
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -245,7 +200,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -254,19 +208,13 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || !target.TryGetTarget(out var t))
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
{
completionSource.TrySetResult(false);
DisposeAsync().Forget();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
TProperty nextValue = default(TProperty);
try
{

View File

@@ -6,32 +6,32 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
{
return new Timer(dueTime, null, updateTiming, ignoreTimeScale, cancelImmediately);
return new Timer(dueTime, null, updateTiming, ignoreTimeScale);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
{
return new Timer(dueTime, period, updateTiming, ignoreTimeScale, cancelImmediately);
return new Timer(dueTime, period, updateTiming, ignoreTimeScale);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
{
return new Timer(period, period, updateTiming, ignoreTimeScale, cancelImmediately);
return new Timer(period, period, updateTiming, ignoreTimeScale);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
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, cancelImmediately);
return new TimerFrame(dueTimeFrameCount, null, updateTiming);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
{
if (dueTimeFrameCount < 0)
{
@@ -42,16 +42,16 @@ namespace Cysharp.Threading.Tasks.Linq
throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancelImmediately);
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
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, cancelImmediately);
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming);
}
}
@@ -61,20 +61,18 @@ namespace Cysharp.Threading.Tasks.Linq
readonly TimeSpan dueTime;
readonly TimeSpan? period;
readonly bool ignoreTimeScale;
readonly bool cancelImmediately;
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, bool cancelImmediately)
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale)
{
this.updateTiming = updateTiming;
this.dueTime = dueTime;
this.period = period;
this.ignoreTimeScale = ignoreTimeScale;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken, cancelImmediately);
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken);
}
class _Timer : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
@@ -83,8 +81,7 @@ namespace Cysharp.Threading.Tasks.Linq
readonly float? period;
readonly PlayerLoopTiming updateTiming;
readonly bool ignoreTimeScale;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
CancellationToken cancellationToken;
int initialFrame;
float elapsed;
@@ -92,7 +89,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed;
bool disposed;
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken, bool cancelImmediately)
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken)
{
this.dueTime = (float)dueTime.TotalSeconds;
this.period = (period == null) ? null : (float?)period.Value.TotalSeconds;
@@ -108,16 +105,6 @@ namespace Cysharp.Threading.Tasks.Linq
this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_Timer)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
}
@@ -127,16 +114,12 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || completed) return CompletedTasks.False;
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
// reset value here.
this.elapsed = 0;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
return new UniTask<bool>(this, completionSource.Version);
}
@@ -144,7 +127,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -153,16 +135,11 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed)
if (disposed || cancellationToken.IsCancellationRequested)
{
completionSource.TrySetResult(false);
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (dueTimePhase)
{
@@ -210,27 +187,24 @@ namespace Cysharp.Threading.Tasks.Linq
readonly PlayerLoopTiming updateTiming;
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
readonly bool cancelImmediately;
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, bool cancelImmediately)
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming)
{
this.updateTiming = updateTiming;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken, cancelImmediately);
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken);
}
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
CancellationToken cancellationToken;
int initialFrame;
int currentFrame;
@@ -238,7 +212,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed;
bool disposed;
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
{
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
if (periodFrameCount != null)
@@ -251,15 +225,6 @@ namespace Cysharp.Threading.Tasks.Linq
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_TimerFrame)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
@@ -269,15 +234,13 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
if (disposed || completed) return CompletedTasks.False;
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
// reset value here.
this.currentFrame = 0;
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -286,7 +249,6 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -295,12 +257,7 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (disposed)
if (disposed || cancellationToken.IsCancellationRequested)
{
completionSource.TrySetResult(false);
return false;

View File

@@ -285,11 +285,7 @@ namespace Cysharp.Threading.Tasks
return dest.ToArray();
}
#if UNITY_2020_1_OR_NEWER
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
#else
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
#endif
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Init()
{
// capture default(unity) sync-context.
@@ -528,14 +524,6 @@ namespace Cysharp.Threading.Tasks
{
sb.AppendFormat("------{0}------", header.type.Name);
sb.AppendLine();
if (header.subSystemList is null)
{
sb.AppendFormat("{0} has no subsystems!", header.ToString());
sb.AppendLine();
continue;
}
foreach (var subSystem in header.subSystemList)
{
sb.AppendFormat("{0}", subSystem.type.Name);
@@ -557,11 +545,6 @@ namespace Cysharp.Threading.Tasks
foreach (var header in playerLoop.subSystemList)
{
if (header.subSystemList is null)
{
continue;
}
foreach (var subSystem in header.subSystemList)
{
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))

View File

@@ -7,7 +7,7 @@ using System.Threading;
namespace Cysharp.Threading.Tasks
{
// internally used but public, allow to user create custom operator with pooling.
// internaly used but public, allow to user create custom operator with pooling.
public static class TaskPool
{

View File

@@ -99,7 +99,7 @@ namespace Cysharp.Threading.Tasks
public void Reset()
{
timer?.Stop();
timer.Stop();
}
public void Dispose()
@@ -109,7 +109,7 @@ namespace Cysharp.Threading.Tasks
try
{
// stop timer.
timer?.Dispose();
timer.Dispose();
// cancel and dispose.
timeoutSource.Cancel();

View File

@@ -20,6 +20,8 @@ namespace Cysharp.Threading.Tasks
{
ITriggerHandler<T> head; // head.prev is last
ITriggerHandler<T> iteratingHead;
bool preserveRemoveSelf;
ITriggerHandler<T> iteratingNode;
void LogError(Exception ex)
@@ -53,9 +55,18 @@ namespace Cysharp.Threading.Tasks
Remove(h);
}
// If `h` itself is removed by OnNext, h.Next is null.
// Therefore, instead of looking at h.Next, the `iteratingNode` reference itself is replaced.
h = h == iteratingNode ? h.Next : iteratingNode;
if (preserveRemoveSelf)
{
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
else
{
h = h.Next;
}
}
iteratingNode = null;
@@ -86,8 +97,9 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
var next = h == iteratingNode ? h.Next : iteratingNode;
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -120,8 +132,9 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
var next = h == iteratingNode ? h.Next : iteratingNode;
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -154,8 +167,9 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
var next = h == iteratingNode ? h.Next : iteratingNode;
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -227,65 +241,71 @@ namespace Cysharp.Threading.Tasks
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
var prev = handler.Prev;
var next = handler.Next;
if (iteratingNode != null && iteratingNode == handler)
{
// if remove self, reserve remove self after invoke completed.
preserveRemoveSelf = true;
}
else
{
var prev = handler.Prev;
var next = handler.Next;
if (next != null)
{
next.Prev = prev;
}
if (handler == head)
{
head = next;
}
// when handler is head, prev indicate last so don't use it.
else if (prev != null)
{
prev.Next = next;
}
if (handler == iteratingNode)
{
iteratingNode = next;
}
if (handler == iteratingHead)
{
iteratingHead = next;
}
if (head != null)
{
if (head.Prev == handler)
if (next != null)
{
if (prev != head)
next.Prev = prev;
}
if (handler == head)
{
head = next;
}
else if (handler == iteratingHead)
{
iteratingHead = next;
}
else
{
// when handler is head, prev indicate last so don't use it.
if (prev != null)
{
head.Prev = prev;
}
else
{
head.Prev = null;
prev.Next = next;
}
}
}
if (iteratingHead != null)
{
if (iteratingHead.Prev == handler)
if (head != null)
{
if (prev != iteratingHead.Prev)
if (head.Prev == handler)
{
iteratingHead.Prev = prev;
}
else
{
iteratingHead.Prev = null;
if (prev != head)
{
head.Prev = prev;
}
else
{
head.Prev = null;
}
}
}
}
handler.Prev = null;
handler.Next = null;
if (iteratingHead != null)
{
if (iteratingHead.Prev == handler)
{
if (prev != iteratingHead.Prev)
{
iteratingHead.Prev = prev;
}
else
{
iteratingHead.Prev = null;
}
}
}
handler.Prev = null;
handler.Next = null;
}
}
}
}

View File

@@ -32,11 +32,13 @@ namespace Cysharp.Threading.Tasks.Triggers
if (cancellationTokenSource == null)
{
cancellationTokenSource = new CancellationTokenSource();
if (!awakeCalled)
{
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
}
}
if (!awakeCalled)
{
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
}
return cancellationTokenSource.Token;
}
}
@@ -81,7 +83,7 @@ namespace Cysharp.Threading.Tasks.Triggers
public bool MoveNext()
{
if (trigger.called || trigger.awakeCalled) return false;
if (trigger.called) return false;
if (trigger == null)
{
trigger.OnDestroy();

View File

@@ -8,16 +8,6 @@ namespace Cysharp.Threading.Tasks
{
public static class UniTaskCancellationExtensions
{
#if UNITY_2022_2_OR_NEWER
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this MonoBehaviour monoBehaviour)
{
return monoBehaviour.destroyCancellationToken;
}
#endif
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
{
@@ -27,13 +17,6 @@ namespace Cysharp.Threading.Tasks
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
{
#if UNITY_2022_2_OR_NEWER
if (component is MonoBehaviour mb)
{
return mb.destroyCancellationToken;
}
#endif
return component.GetAsyncDestroyTrigger().CancellationToken;
}
}

View File

@@ -2,7 +2,6 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Threading;
using UnityEngine;
@@ -33,14 +32,14 @@ namespace Cysharp.Threading.Tasks
return new YieldAwaitable(timing);
}
public static UniTask Yield(CancellationToken cancellationToken, bool cancelImmediately = false)
public static UniTask Yield(CancellationToken cancellationToken)
{
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
}
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken)
{
return new UniTask(YieldPromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token);
}
/// <summary>
@@ -48,7 +47,7 @@ namespace Cysharp.Threading.Tasks
/// </summary>
public static UniTask NextFrame()
{
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, false, out var token), token);
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, out var token), token);
}
/// <summary>
@@ -56,113 +55,87 @@ namespace Cysharp.Threading.Tasks
/// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing)
{
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, false, out var token), token);
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, out var token), token);
}
/// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary>
public static UniTask NextFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
public static UniTask NextFrame(CancellationToken cancellationToken)
{
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
}
/// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken)
{
return new UniTask(NextFramePromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
}
#if UNITY_2023_1_OR_NEWER
public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default)
{
await Awaitable.EndOfFrameAsync(cancellationToken);
}
#else
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate).
/// </summary>
public static YieldAwaitable WaitForEndOfFrame()
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
}
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken)
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
}
#endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{
var source = WaitForEndOfFramePromise.Create(coroutineRunner, CancellationToken.None, false, out var token);
return new UniTask(source, token);
}
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately = false)
{
var source = WaitForEndOfFramePromise.Create(coroutineRunner, cancellationToken, cancelImmediately, out var token);
return new UniTask(source, token);
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate).
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate).
/// </summary>
public static YieldAwaitable WaitForFixedUpdate()
{
// use LastFixedUpdate instead of FixedUpdate
// https://github.com/Cysharp/UniTask/issues/377
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate);
return UniTask.Yield(PlayerLoopTiming.FixedUpdate);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken).
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken, bool cancelImmediately = false)
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken)
{
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken, cancelImmediately);
return UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken);
}
public static UniTask WaitForSeconds(float duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return Delay(Mathf.RoundToInt(1000 * duration), ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask WaitForSeconds(int duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return Delay(1000 * duration, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
if (delayFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount);
}
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, out var token), token);
}
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
}
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
}
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
}
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
if (delayTimeSpan < TimeSpan.Zero)
{
@@ -181,16 +154,16 @@ namespace Cysharp.Threading.Tasks
{
case DelayType.UnscaledDeltaTime:
{
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
case DelayType.Realtime:
{
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
case DelayType.DeltaTime:
default:
{
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
}
}
}
@@ -207,14 +180,13 @@ namespace Cysharp.Threading.Tasks
}
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
YieldPromise()
{
}
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -226,16 +198,8 @@ namespace Cysharp.Threading.Tasks
result = new YieldPromise();
}
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (YieldPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -289,7 +253,6 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -306,15 +269,14 @@ namespace Cysharp.Threading.Tasks
}
int frameCount;
UniTaskCompletionSourceCore<AsyncUnit> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncUnit> core;
NextFramePromise()
{
}
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -329,15 +291,6 @@ namespace Cysharp.Threading.Tasks
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (NextFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -395,129 +348,10 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
sealed class WaitForEndOfFramePromise : IUniTaskSource, ITaskPoolNode<WaitForEndOfFramePromise>, System.Collections.IEnumerator
{
static TaskPool<WaitForEndOfFramePromise> pool;
WaitForEndOfFramePromise nextNode;
public ref WaitForEndOfFramePromise NextNode => ref nextNode;
static WaitForEndOfFramePromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitForEndOfFramePromise), () => pool.Size);
}
UniTaskCompletionSourceCore<object> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
WaitForEndOfFramePromise()
{
}
public static IUniTaskSource Create(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitForEndOfFramePromise();
}
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitForEndOfFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
coroutineRunner.StartCoroutine(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);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
Reset(); // Reset Enumerator
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
// Coroutine Runner implementation
static readonly WaitForEndOfFrame waitForEndOfFrameYieldInstruction = new WaitForEndOfFrame();
bool isFirst = true;
object IEnumerator.Current => waitForEndOfFrameYieldInstruction;
bool IEnumerator.MoveNext()
{
if (isFirst)
{
isFirst = false;
return true; // start WaitForEndOfFrame
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
core.TrySetResult(null);
return false;
}
public void Reset()
{
isFirst = true;
}
}
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
{
static TaskPool<DelayFramePromise> pool;
@@ -532,7 +366,6 @@ namespace Cysharp.Threading.Tasks
int initialFrame;
int delayFrameCount;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
int currentFrameCount;
UniTaskCompletionSourceCore<AsyncUnit> core;
@@ -541,7 +374,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -557,15 +390,6 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -620,19 +444,7 @@ namespace Cysharp.Threading.Tasks
// skip in initial frame.
if (initialFrame == Time.frameCount)
{
#if UNITY_EDITOR
// force use Realtime.
if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
{
//goto ++currentFrameCount
}
else
{
return true;
}
#else
return true;
#endif
}
}
@@ -652,7 +464,6 @@ namespace Cysharp.Threading.Tasks
currentFrameCount = default;
delayFrameCount = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -672,7 +483,6 @@ namespace Cysharp.Threading.Tasks
float delayTimeSpan;
float elapsed;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
@@ -680,7 +490,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -697,15 +507,6 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -774,7 +575,6 @@ namespace Cysharp.Threading.Tasks
delayTimeSpan = default;
elapsed = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -794,7 +594,6 @@ namespace Cysharp.Threading.Tasks
float elapsed;
int initialFrame;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
@@ -802,7 +601,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -819,15 +618,6 @@ namespace Cysharp.Threading.Tasks
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayIgnoreTimeScalePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -896,7 +686,6 @@ namespace Cysharp.Threading.Tasks
delayFrameTimeSpan = default;
elapsed = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -915,7 +704,6 @@ namespace Cysharp.Threading.Tasks
long delayTimeSpanTicks;
ValueStopwatch stopwatch;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncUnit> core;
@@ -923,7 +711,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -939,15 +727,6 @@ namespace Cysharp.Threading.Tasks
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayRealtimePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -1012,7 +791,6 @@ namespace Cysharp.Threading.Tasks
core.Reset();
stopwatch = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}

View File

@@ -194,7 +194,6 @@ namespace Cysharp.Threading.Tasks
sealed class ExceptionResultSource : IUniTaskSource
{
readonly ExceptionDispatchInfo exception;
bool calledGet;
public ExceptionResultSource(Exception exception)
{
@@ -203,11 +202,6 @@ namespace Cysharp.Threading.Tasks
public void GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
}
@@ -225,20 +219,11 @@ namespace Cysharp.Threading.Tasks
{
continuation(state);
}
~ExceptionResultSource()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
{
readonly ExceptionDispatchInfo exception;
bool calledGet;
public ExceptionResultSource(Exception exception)
{
@@ -247,22 +232,12 @@ namespace Cysharp.Threading.Tasks
public T GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
return default;
}
void IUniTaskSource.GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
}
@@ -280,14 +255,6 @@ namespace Cysharp.Threading.Tasks
{
continuation(state);
}
~ExceptionResultSource()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
sealed class CanceledResultSource : IUniTaskSource

View File

@@ -9,56 +9,237 @@ namespace Cysharp.Threading.Tasks
{
#region OBSOLETE_RUN
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
// Run is a confusing name, use only RunOnThreadPool in the future.
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(action, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
action();
}
finally
{
await UniTask.Yield();
}
}
else
{
action();
}
cancellationToken.ThrowIfCancellationRequested();
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
action(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
action(state);
}
cancellationToken.ThrowIfCancellationRequested();
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(action, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
await action();
}
finally
{
await UniTask.Yield();
}
}
else
{
await action();
}
cancellationToken.ThrowIfCancellationRequested();
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
await action(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
await action(state);
}
cancellationToken.ThrowIfCancellationRequested();
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(func, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return func();
}
finally
{
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
return func();
}
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(func, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return await func();
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
var result = await func();
cancellationToken.ThrowIfCancellationRequested();
return result;
}
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return func(state);
}
finally
{
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
return func(state);
}
}
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return await func(state);
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
var result = await func(state);
cancellationToken.ThrowIfCancellationRequested();
return result;
}
}
#endregion
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
{

View File

@@ -9,30 +9,30 @@ namespace Cysharp.Threading.Tasks
{
public partial struct UniTask
{
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, out var token), token);
}
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, out var token), token);
}
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update)
{
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, out var token), token);
}
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken))
where T : class
{
var unityObject = target as UnityEngine.Object;
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
return new UniTask<U>(isUnityObject
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out var token)
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out token), token);
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token)
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
}
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
@@ -48,7 +48,6 @@ namespace Cysharp.Threading.Tasks
Func<bool> predicate;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
@@ -56,7 +55,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -71,15 +70,6 @@ namespace Cysharp.Threading.Tasks
result.predicate = predicate;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -146,7 +136,6 @@ namespace Cysharp.Threading.Tasks
core.Reset();
predicate = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -164,7 +153,6 @@ namespace Cysharp.Threading.Tasks
Func<bool> predicate;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
@@ -172,7 +160,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -186,15 +174,6 @@ namespace Cysharp.Threading.Tasks
result.predicate = predicate;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitWhilePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -262,7 +241,6 @@ namespace Cysharp.Threading.Tasks
core.Reset();
predicate = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -279,7 +257,6 @@ namespace Cysharp.Threading.Tasks
}
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core;
@@ -287,7 +264,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool completeImmediately, out short token)
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -301,15 +278,6 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
if (completeImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilCanceledPromise)state;
promise.core.TrySetResult(null);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
@@ -361,7 +329,6 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -384,7 +351,6 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<U> core;
@@ -392,7 +358,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -410,15 +376,6 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedUnityObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -496,7 +453,6 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default;
equalityComparer = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -518,7 +474,6 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<U> core;
@@ -526,7 +481,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -543,15 +498,6 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedStandardObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -629,7 +575,6 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default;
equalityComparer = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}

View File

@@ -69,7 +69,7 @@ namespace Cysharp.Threading.Tasks
return new UniTask<bool>(new IsCanceledSource(source), token);
}
#if !UNITY_2018_3_OR_NEWER || UNITY_2021_2_OR_NEWER
#if !UNITY_2018_3_OR_NEWER
public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
{
@@ -440,7 +440,7 @@ namespace Cysharp.Threading.Tasks
return self.AsUniTask();
}
#if !UNITY_2018_3_OR_NEWER || UNITY_2021_2_OR_NEWER
#if !UNITY_2018_3_OR_NEWER
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
{

View File

@@ -137,8 +137,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -165,8 +165,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -184,8 +184,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -328,7 +328,6 @@ namespace Cysharp.Threading.Tasks
}
UniTaskCompletionSourceCore<AsyncUnit> core;
short version;
AutoResetUniTaskCompletionSource()
{
@@ -341,7 +340,6 @@ namespace Cysharp.Threading.Tasks
{
result = new AutoResetUniTaskCompletionSource();
}
result.version = result.core.Version;
TaskTracker.TrackActiveTask(result, 2);
return result;
}
@@ -385,19 +383,19 @@ namespace Cysharp.Threading.Tasks
[DebuggerHidden]
public bool TrySetResult()
{
return version == core.Version && core.TrySetResult(AsyncUnit.Default);
return core.TrySetResult(AsyncUnit.Default);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return version == core.Version && core.TrySetCanceled(cancellationToken);
return core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return version == core.Version && core.TrySetException(exception);
return core.TrySetException(exception);
}
[DebuggerHidden]
@@ -411,6 +409,7 @@ namespace Cysharp.Threading.Tasks
{
TryReturn();
}
}
[DebuggerHidden]
@@ -452,7 +451,6 @@ namespace Cysharp.Threading.Tasks
}
UniTaskCompletionSourceCore<T> core;
short version;
AutoResetUniTaskCompletionSource()
{
@@ -465,7 +463,6 @@ namespace Cysharp.Threading.Tasks
{
result = new AutoResetUniTaskCompletionSource<T>();
}
result.version = result.core.Version;
TaskTracker.TrackActiveTask(result, 2);
return result;
}
@@ -509,19 +506,19 @@ namespace Cysharp.Threading.Tasks
[DebuggerHidden]
public bool TrySetResult(T result)
{
return version == core.Version && core.TrySetResult(result);
return core.TrySetResult(result);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return version == core.Version && core.TrySetCanceled(cancellationToken);
return core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return version == core.Version && core.TrySetException(exception);
return core.TrySetException(exception);
}
[DebuggerHidden]
@@ -940,5 +937,5 @@ namespace Cysharp.Threading.Tasks
}
return false;
}
}
}
}

View File

@@ -28,7 +28,7 @@ namespace Cysharp.Threading.Tasks
p.TrySetCanceled();
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception.InnerException ?? x.Exception);
p.TrySetException(x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult(x.Result);
@@ -58,7 +58,7 @@ namespace Cysharp.Threading.Tasks
p.TrySetCanceled();
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception.InnerException ?? x.Exception);
p.TrySetException(x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult();
@@ -454,7 +454,7 @@ namespace Cysharp.Threading.Tasks
}
/// <summary>
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCanceled).
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
/// </summary>
public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
{

View File

@@ -74,19 +74,16 @@ namespace Cysharp.Threading.Tasks
static async UniTaskVoid Fire<T>(AsyncSubject<T> subject, UniTask<T> task)
{
T value;
try
{
value = await task;
var value = await task;
subject.OnNext(value);
subject.OnCompleted();
}
catch (Exception ex)
{
subject.OnError(ex);
return;
}
subject.OnNext(value);
subject.OnCompleted();
}
static async UniTaskVoid Fire(AsyncSubject<AsyncUnit> subject, UniTask task)
@@ -94,15 +91,13 @@ namespace Cysharp.Threading.Tasks
try
{
await task;
subject.OnNext(AsyncUnit.Default);
subject.OnCompleted();
}
catch (Exception ex)
{
subject.OnError(ex);
return;
}
subject.OnNext(AsyncUnit.Default);
subject.OnCompleted();
}
class ToUniTaskObserver<T> : IObserver<T>
@@ -133,7 +128,7 @@ namespace Cysharp.Threading.Tasks
{
var self = (ToUniTaskObserver<T>)state;
self.disposable.Dispose();
self.promise.TrySetCanceled(self.cancellationToken);
self.promise.TrySetCanceled();
}
public void OnNext(T value)
@@ -203,7 +198,7 @@ namespace Cysharp.Threading.Tasks
{
var self = (FirstValueToUniTaskObserver<T>)state;
self.disposable.Dispose();
self.promise.TrySetCanceled(self.cancellationToken);
self.promise.TrySetCanceled();
}
public void OnNext(T value)

View File

@@ -21,20 +21,15 @@ namespace Cysharp.Threading.Tasks
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
{
return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken);
return AwaitForAllAssets(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return AwaitForAllAssets(asyncOperation, progress: null, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
@@ -100,19 +95,15 @@ namespace Cysharp.Threading.Tasks
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
Action<AsyncOperation> continuationAction;
AssetBundleRequestAllAssetsConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -127,18 +118,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleRequestAllAssetsConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -182,12 +161,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -215,29 +188,8 @@ namespace Cysharp.Threading.Tasks
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.allAssets);
}
}
}
}
}
}

View File

@@ -20,17 +20,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token);
}
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
{
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
@@ -44,15 +39,15 @@ namespace Cysharp.Threading.Tasks
AsyncGPUReadbackRequest asyncOperation;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
AsyncGPUReadbackRequestAwaiterConfiguredSource()
{
}
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -66,15 +61,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncGPUReadbackRequestAwaiterConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -145,7 +131,6 @@ namespace Cysharp.Threading.Tasks
core.Reset();
asyncOperation = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}

View File

@@ -15,31 +15,23 @@ namespace Cysharp.Threading.Tasks
{
#region AsyncOperation
#if !UNITY_2023_1_OR_NEWER
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
return new AsyncOperationAwaiter(asyncOperation);
}
#endif
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
if (asyncOperation.isDone) return UniTask.CompletedTask;
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
@@ -96,19 +88,15 @@ namespace Cysharp.Threading.Tasks
AsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
Action<AsyncOperation> continuationAction;
AsyncOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -123,18 +111,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AsyncOperationConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -174,12 +150,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -204,33 +174,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
}
}
}
#endregion
@@ -248,17 +196,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
@@ -319,19 +262,15 @@ namespace Cysharp.Threading.Tasks
ResourceRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
Action<AsyncOperation> continuationAction;
ResourceRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -346,18 +285,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (ResourceRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -401,12 +328,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -431,33 +352,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.asset);
}
}
}
}
#endregion
@@ -476,17 +375,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
@@ -547,19 +441,15 @@ namespace Cysharp.Threading.Tasks
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
Action<AsyncOperation> continuationAction;
AssetBundleRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -574,18 +464,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -629,12 +507,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -659,33 +531,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.asset);
}
}
}
}
#endregion
@@ -705,17 +555,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
@@ -776,19 +621,15 @@ namespace Cysharp.Threading.Tasks
AssetBundleCreateRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<AssetBundle> core;
Action<AsyncOperation> continuationAction;
AssetBundleCreateRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -803,18 +644,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleCreateRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -858,12 +687,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -888,33 +711,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.assetBundle);
}
}
}
}
#endregion
@@ -934,12 +735,7 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
@@ -951,7 +747,7 @@ namespace Cysharp.Threading.Tasks
}
return UniTask.FromResult(asyncOperation.webRequest);
}
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
@@ -1020,19 +816,15 @@ namespace Cysharp.Threading.Tasks
UnityWebRequestAsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<UnityWebRequest> core;
Action<AsyncOperation> continuationAction;
UnityWebRequestAsyncOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -1047,19 +839,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (UnityWebRequestAsyncOperationConfiguredSource)state;
source.asyncOperation.webRequest.Abort();
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -1103,12 +882,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
asyncOperation.webRequest.Abort();
@@ -1141,37 +914,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (asyncOperation.webRequest.IsError())
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
}
}
}
#endregion

View File

@@ -16,7 +16,6 @@
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
Func<(string typeName, string returnType, string returnField), bool> IsAsyncOperationBase = x => x.typeName == "AsyncOperation";
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
Func<(string typeName, string returnType, string returnField), bool> IsAssetBundleModule = x => x.typeName == "AssetBundleRequest" || x.typeName == "AssetBundleCreateRequest";
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
@@ -44,30 +43,18 @@ namespace Cysharp.Threading.Tasks
<# } #>
#region <#= t.typeName #>
<# if (IsAsyncOperationBase(t)) { #>
#if !UNITY_2023_1_OR_NEWER
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
<# } #>
public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
return new <#= t.typeName #>Awaiter(asyncOperation);
}
<# if (IsAsyncOperationBase(t)) { #>
#endif
<# } #>
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
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));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
@@ -83,7 +70,7 @@ namespace Cysharp.Threading.Tasks
<# } else { #>
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, cancelImmediately, out var token), token);
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
}
public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion
@@ -164,19 +151,15 @@ namespace Cysharp.Threading.Tasks
<#= t.typeName #> asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool completed;
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
Action<AsyncOperation> continuationAction;
<#= t.typeName #>ConfiguredSource()
{
continuationAction = Continuation;
}
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -191,21 +174,6 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (<#= t.typeName #>ConfiguredSource)state;
<# if(IsUnityWebRequest(t)) { #>
source.asyncOperation.webRequest.Abort();
<# } #>
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -255,12 +223,6 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
<# if(IsUnityWebRequest(t)) { #>
@@ -299,44 +261,11 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
TryReturn();
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
<# if(IsUnityWebRequest(t)) { #>
else if (asyncOperation.webRequest.IsError())
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
<# } else { #>
else
{
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
}
<# } #>
}
}
}
#endregion

View File

@@ -673,7 +673,7 @@ namespace Cysharp.Threading.Tasks
}
if (cancellationToken2.CanBeCanceled)
{
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
}
}
@@ -688,27 +688,13 @@ namespace Cysharp.Threading.Tasks
static void OnCanceled1(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
try
{
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
finally
{
self.DisposeAsync().Forget();
}
self.DisposeAsync().Forget();
}
static void OnCanceled2(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
try
{
self.completionSource.TrySetCanceled(self.cancellationToken2);
}
finally
{
self.DisposeAsync().Forget();
}
self.DisposeAsync().Forget();
}
public UniTask DisposeAsync()
@@ -720,8 +706,6 @@ namespace Cysharp.Threading.Tasks
registration1.Dispose();
registration2.Dispose();
unityEvent.RemoveListener(unityAction);
completionSource.TrySetCanceled();
}
return default;
@@ -793,7 +777,7 @@ namespace Cysharp.Threading.Tasks
}
if (cancellationToken2.CanBeCanceled)
{
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
}
}
@@ -809,27 +793,13 @@ namespace Cysharp.Threading.Tasks
static void OnCanceled1(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
try
{
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
finally
{
self.DisposeAsync().Forget();
}
self.DisposeAsync().Forget();
}
static void OnCanceled2(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
try
{
self.completionSource.TrySetCanceled(self.cancellationToken2);
}
finally
{
self.DisposeAsync().Forget();
}
self.DisposeAsync().Forget();
}
public UniTask DisposeAsync()
@@ -845,8 +815,6 @@ namespace Cysharp.Threading.Tasks
disp.Dispose();
}
unityEvent.RemoveListener(unityAction);
completionSource.TrySetCanceled();
}
return default;

View File

@@ -1,17 +0,0 @@
#if UNITY_2023_1_OR_NEWER
namespace Cysharp.Threading.Tasks
{
public static class UnityAwaitableExtensions
{
public static async UniTask AsUniTask(this UnityEngine.Awaitable awaitable)
{
await awaitable;
}
public static async UniTask<T> AsUniTask<T>(this UnityEngine.Awaitable<T> awaitable)
{
return await awaitable;
}
}
}
#endif

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: c29533c9e4284dee914b71a6579ea274
timeCreated: 1698895807

View File

@@ -12,17 +12,17 @@ namespace Cysharp.Threading.Tasks
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
// <string> -> Text
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, bool rebindOnError = true)
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:
@@ -68,22 +68,22 @@ namespace Cysharp.Threading.Tasks
// <T> -> Text
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
public static void BindTo<T>(this AsyncReactiveProperty<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
public static void BindTo<T>(this AsyncReactiveProperty<T> source, Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:

View File

@@ -1,4 +1,4 @@
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
using System;
using System.Collections.Generic;
@@ -49,7 +49,7 @@ namespace Cysharp.Threading.Tasks
{
if (msg == null)
{
if(!string.IsNullOrWhiteSpace(Text))
if (Text != null)
{
msg = Error + Environment.NewLine + Text;
}

View File

@@ -1,12 +1,11 @@
{
"name": "com.cysharp.unitask",
"displayName": "UniTask",
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
"version": "2.5.1",
"version": "2.2.5",
"unity": "2018.4",
"description": "Provides an efficient async/await integration to Unity.",
"keywords": [ "async/await", "async", "Task", "UniTask" ],
"license": "MIT",
"category": "Task",
"dependencies": {}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8d82913edf6ac48aca30f66ae9ba42d6
guid: 8fb84ce71736dab41b0cca7ea3f5b313
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1 @@
bar

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9df64c494bee73b40ad3679f44bbc8c5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1 @@
baz

View File

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

View File

@@ -0,0 +1 @@
foo

View File

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

View File

@@ -0,0 +1,129 @@
using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class DemoScript : MonoBehaviour
{
public Toggle toggle = null;
public Text text = null;
async Task Start()
{
text.text = "";
var result = await DemoAsync();
text.text = $"RESULT is: {result}";
}
async UniTask<string> DemoAsync()
{
// You can await Unity's AsyncObject
text.text = "loading assets";
var asset = await Resources.LoadAsync<TextAsset>("foo");
text.text = "get data from github.com";
var txt = (await UnityWebRequest.Get("https://github.com").SendWebRequest()).downloadHandler.text;
text.text = "load scene2";
await SceneManager.LoadSceneAsync("scene2", LoadSceneMode.Additive);
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
text.text = "load text asset bar";
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>
text.text = "load text asset baz";
var asset3 = await Resources.LoadAsync<TextAsset>("baz").ToUniTask(Progress.Create<float>(x => Debug.Log(x)));
// await frame-based operation like a coroutine
text.text = "delay frame";
await UniTask.DelayFrame(100);
// replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
text.text = "wait 3sec.";
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: false);
// yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)
text.text = "wait for PreLateUpdate";
await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);
// replacement of yield return null
text.text = "yield";
await UniTask.Yield();
text.text = "wait nextframe";
await UniTask.NextFrame();
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
text.text = "wait end of frame";
await UniTask.WaitForEndOfFrame();
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
text.text = "wait fixed update";
await UniTask.WaitForFixedUpdate();
// replacement of yield return WaitUntil
text.text = "wait for toggle => false";
await UniTask.WaitUntil(() => toggle.isOn == false);
// special helper of WaitUntil
text.text = "wait for toggle";
await UniTask.WaitUntilValueChanged(this, x => toggle.isOn);
// You can await IEnumerator coroutines
text.text = "corouting";
await FooCoroutineEnumerator();
// You can await a standard task
text.text = "run standard task";
await Task.Run(() => 100);
// Multithreading, run on ThreadPool under this code
text.text = "switch to thread pool";
await UniTask.SwitchToThreadPool();
/* work on ThreadPool */
// return to MainThread(same as `ObserveOnMainThread` in UniRx)
await UniTask.SwitchToMainThread();
text.text = "switch to main pool";
// get async webrequest
async UniTask<string> GetTextAsync(UnityWebRequest req)
{
var op = await req.SendWebRequest();
return op.downloadHandler.text;
}
var task1 = GetTextAsync(UnityWebRequest.Get("https://google.com/"));
var task2 = GetTextAsync(UnityWebRequest.Get("https://bing.com/"));
var task3 = GetTextAsync(UnityWebRequest.Get("https://yahoo.com/"));
// concurrent async-wait and get results easily by tuple syntax
text.text = "get data from google,bing,yahoo (concurrent)";
var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3);
// can not call same task twice. let's define again for simple demo.
var tasknew1 = GetTextAsync(UnityWebRequest.Get("https://google.com/"));
var tasknew2 = GetTextAsync(UnityWebRequest.Get("https://bing.com/"));
var tasknew3 = GetTextAsync(UnityWebRequest.Get("https://yahoo.com/"));
// shorthand of WhenAll, tuple can await directly.
text.text = "get data from google,bing,yahoo (shorthand)";
var (google2, bing2, yahoo2) = await (tasknew1, tasknew2, tasknew3);
// return async-value.(or you can use `UniTask`(no result), `UniTaskVoid`(fire and forget)).
text.text = "return asset result";
return (asset as TextAsset)?.text ?? throw new InvalidOperationException("Asset not found");
}
private IEnumerator FooCoroutineEnumerator()
{
Debug.Log("cotoutine 1");
yield return new WaitForSeconds(1);
Debug.Log("cotoutine 2");
yield return new WaitForSeconds(1);
Debug.Log("cotoutine end");
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d38f0478933be42d895c37b862540a1c
guid: 3defd278e9f50124396082efc492cb81
MonoImporter:
externalObjects: {}
serializedVersion: 2

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -543,7 +543,7 @@ public class SandboxMain : MonoBehaviour
Debug.LogError(e);
return;
}
}
Debug.Log("TestAsync Finished.");
@@ -555,7 +555,6 @@ public class SandboxMain : MonoBehaviour
async UniTaskVoid Start()
{
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
@@ -563,34 +562,61 @@ public class SandboxMain : MonoBehaviour
PlayerLoopHelper.Initialize(ref currentLoop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate
var cancelToken = new CancellationTokenSource();
cancelButton.onClick.AddListener(()=>
{
cancelToken.Cancel(); // cancel from button click.
});
var timeoutToken = new CancellationTokenSource();
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
try
{
// combine token
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, timeoutToken.Token);
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(linkedTokenSource.Token);
}
catch (OperationCanceledException ex)
{
if (timeoutToken.IsCancellationRequested)
{
UnityEngine.Debug.Log("Timeout.");
}
else if (cancelToken.IsCancellationRequested)
{
UnityEngine.Debug.Log("Cancel clicked.");
}
_ = ex;
}
// TestAsync(cts.Token).Forget();
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
await UniTask.WaitForEndOfFrame(this);
var texture = new Texture2D(Screen.width, Screen.height);
texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
texture.Apply();
// try timeout
try
{
//await UniTask.Delay(TimeSpan.FromSeconds(2), cancellationToken: timeoutController.Timeout(TimeSpan.FromSeconds(3)));
UnityEngine.Debug.Log("Delay Complete, Reset(and reuse).");
//timeoutController.Reset();
}
catch (OperationCanceledException ex)
{
//UnityEngine.Debug.Log("Timeout! FromTimeout?:" + timeoutController.IsTimeout());
_ = ex;
}
var jpg = texture.EncodeToJPG();
File.WriteAllBytes("testscreencapture.jpg", jpg);
Debug.Log("ok?");
//var texture = ScreenCapture.CaptureScreenshotAsTexture();
//if (texture == null)
//{
// Debug.Log("fail");
//}
//else
//{
// var jpg = texture.EncodeToJPG();
// File.WriteAllBytes("testscreencapture.jpg", jpg);
// Debug.Log("ok?");
//}
await UniTask.Yield();
}));
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>

View File

@@ -0,0 +1,299 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &386714
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 386717}
- component: {fileID: 386716}
- component: {fileID: 386715}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!81 &386715
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 386714}
m_Enabled: 1
--- !u!20 &386716
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 386714}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &386717
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 386714}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &172792889
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 172792893}
- component: {fileID: 172792892}
- component: {fileID: 172792891}
- component: {fileID: 172792890}
m_Layer: 0
m_Name: Cube
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &172792890
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 172792889}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &172792891
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 172792889}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!33 &172792892
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 172792889}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &172792893
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 172792889}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

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

View File

@@ -1,90 +0,0 @@
using System.Collections;
using System.Threading;
using Cysharp.Threading.Tasks;
using FluentAssertions;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.TestTools;
#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
namespace Cysharp.Threading.TasksTests
{
public class AsyncOperationTest
{
[UnityTest]
public IEnumerator ResourcesLoad_Completed() => UniTask.ToCoroutine(async () =>
{
var asyncOperation = Resources.LoadAsync<Texture2D>("sample_texture");
await asyncOperation.ToUniTask();
asyncOperation.isDone.Should().BeTrue();
asyncOperation.asset.GetType().Should().Be(typeof(Texture2D));
});
[UnityTest]
public IEnumerator ResourcesLoad_CancelOnPlayerLoop() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
var task = Resources.LoadAsync<Texture>("sample_texture").ToUniTask(cancellationToken: cts.Token, cancelImmediately: false);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Pending);
await UniTask.NextFrame();
task.Status.Should().Be(UniTaskStatus.Canceled);
});
[Test]
public void ResourcesLoad_CancelImmediately()
{
{
var cts = new CancellationTokenSource();
var task = Resources.LoadAsync<Texture>("sample_texture").ToUniTask(cancellationToken: cts.Token, cancelImmediately: true);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
[UnityTest]
public IEnumerator UnityWebRequest_Completed() => UniTask.ToCoroutine(async () =>
{
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var asyncOperation = UnityWebRequest.Get($"file://{filePath}").SendWebRequest();
await asyncOperation.ToUniTask();
asyncOperation.isDone.Should().BeTrue();
asyncOperation.webRequest.result.Should().Be(UnityWebRequest.Result.Success);
});
[UnityTest]
public IEnumerator UnityWebRequest_CancelOnPlayerLoop() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var task = UnityWebRequest.Get($"file://{filePath}").SendWebRequest().ToUniTask(cancellationToken: cts.Token);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Pending);
await UniTask.NextFrame();
task.Status.Should().Be(UniTaskStatus.Canceled);
});
[Test]
public void UnityWebRequest_CancelImmediately()
{
var cts = new CancellationTokenSource();
cts.Cancel();
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var task = UnityWebRequest.Get($"file://{filePath}").SendWebRequest().ToUniTask(cancellationToken: cts.Token, cancelImmediately: true);
task.Status.Should().Be(UniTaskStatus.Canceled);
}
#endif
}
}
#endif

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 295d574a16494d6aa4d02fcb32179e39
timeCreated: 1698887128

View File

@@ -310,33 +310,33 @@ namespace Cysharp.Threading.TasksTests
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 () =>
@@ -366,29 +366,6 @@ namespace Cysharp.Threading.TasksTests
UniTaskScheduler.UnobservedTaskException -= action;
});
// can not run on RuntimeUnitTestToolkit so ignore...
// [UnityTest]
// public IEnumerator ThrowExceptionUnawaited() => UniTask.ToCoroutine(async () =>
// {
// LogAssert.Expect(LogType.Exception, "Exception: MyException");
//#pragma warning disable 1998
// async UniTask Throw() => throw new Exception("MyException");
//#pragma warning restore 1998
//#pragma warning disable 4014
// Throw();
//#pragma warning restore 4014
// await UniTask.DelayFrame(3);
// GC.Collect();
// GC.WaitForPendingFinalizers();
// GC.Collect();
// await UniTask.DelayFrame(1);
// });
async UniTask InException1()
{
await UniTask.Yield();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,208 +0,0 @@
fileFormatVersion: 2
guid: 535006a83baed4ebda99d24a909a2efe
TextureImporter:
internalIDToNameTable:
- first:
213: -2664112245596591751
second: sample_texture_0
- first:
213: -4606777057269188692
second: sample_texture_1
- first:
213: 1950921086533113773
second: sample_texture_2
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: sample_texture_0
rect:
serializedVersion: 2
x: 0
y: 76
width: 243
height: 251
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: 9796277170c270bd0800000000000000
internalID: -2664112245596591751
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sample_texture_1
rect:
serializedVersion: 2
x: 227
y: 0
width: 190
height: 231
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: ca7fc069ca07110c0800000000000000
internalID: -4606777057269188692
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sample_texture_2
rect:
serializedVersion: 2
x: 398
y: 87
width: 202
height: 188
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: da710ab4460131b10800000000000000
internalID: 1950921086533113773
vertices: []
indices:
edges: []
weights: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -11,4 +11,10 @@ EditorBuildSettings:
- enabled: 1
path: Assets/Scenes/ExceptionExamples.unity
guid: b5fed17e3ece238439bc796d8747df5d
- enabled: 1
path: Assets/Scenes/SampleScene.unity
guid: edc485cde0ff14046a21a7c2a51bb0ac
- enabled: 1
path: Assets/Scenes/scene2.unity
guid: 84d1cc7b4b33fa54f98a29e843b1db30
m_configObjects: {}

View File

@@ -8,6 +8,9 @@ EditorUserSettings:
RecentlyUsedScenePath-0:
value: 22424703114646680e0b0227036c6c1118131a25340527392367083debf42d
flags: 0
RecentlyUsedScenePath-1:
value: 22424703114646680e0b0227036c6c111b07142f1f2b233e2867083debf42d
flags: 0
vcSharedLogLevel:
value: 0d5e400f0650
flags: 0