mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 11:30:09 +00:00
Compare commits
322 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b992a061fb | ||
|
|
4fc09a6f61 | ||
|
|
e57176a43c | ||
|
|
710d0d9012 | ||
|
|
039de3ef65 | ||
|
|
de38f63a55 | ||
|
|
38f8193199 | ||
|
|
15cffb7357 | ||
|
|
d55748e05b | ||
|
|
5602861dd4 | ||
|
|
d2245bc38b | ||
|
|
f092f6a112 | ||
|
|
ed617a04a6 | ||
|
|
340736795c | ||
|
|
dc804ffb13 | ||
|
|
a879989d1c | ||
|
|
ee54559532 | ||
|
|
4a72ec2a1a | ||
|
|
e999268305 | ||
|
|
8300c1b1e6 | ||
|
|
daa0c7b9a0 | ||
|
|
9b9a4ec76a | ||
|
|
3f8e43b83f | ||
|
|
cf6f0799e9 | ||
|
|
91ba4f003a | ||
|
|
f48cb4b03e | ||
|
|
70a243d978 | ||
|
|
9b95f3b9f6 | ||
|
|
a25adb601b | ||
|
|
e6240879c4 | ||
|
|
a94e8cceac | ||
|
|
0595a4182a | ||
|
|
df96c119c1 | ||
|
|
534f4a2588 | ||
|
|
873485ad1a | ||
|
|
f6037d6c9b | ||
|
|
78db78c7bd | ||
|
|
226e272787 | ||
|
|
9e2163616b | ||
|
|
52df6fbf3f | ||
|
|
33d32baea4 | ||
|
|
b0250cfe75 | ||
|
|
7a35f121cd | ||
|
|
79f1566fdb | ||
|
|
364b67805d | ||
|
|
62ca0c6e92 | ||
|
|
f63212aa17 | ||
|
|
768fd16e60 | ||
|
|
3c99010ba0 | ||
|
|
5c668717d8 | ||
|
|
b089f74c65 | ||
|
|
fcf4f21cc1 | ||
|
|
ee2fd3e91d | ||
|
|
27604496ca | ||
|
|
0d01034a57 | ||
|
|
50a67d8f41 | ||
|
|
2a23a85cdd | ||
|
|
e127d9976e | ||
|
|
c31b78e45e | ||
|
|
b6b0b4000d | ||
|
|
69be818a46 | ||
|
|
a1dee8b54f | ||
|
|
4f6166102d | ||
|
|
6b1d2c231a | ||
|
|
0715dd31bf | ||
|
|
26dbfa3655 | ||
|
|
6ac55e37a1 | ||
|
|
60bfbae787 | ||
|
|
fc9ddeb15c | ||
|
|
dfe18d11ff | ||
|
|
958a8e11ab | ||
|
|
257186313b | ||
|
|
5bd508b31c | ||
|
|
9e18ba332e | ||
|
|
946b9003f0 | ||
|
|
ffa55becf3 | ||
|
|
72e620d169 | ||
|
|
10ebddf892 | ||
|
|
c51e45ee21 | ||
|
|
6968faf35b | ||
|
|
4fc9ca315e | ||
|
|
aaf1c0eaa1 | ||
|
|
44ce3c96bb | ||
|
|
03097f08e2 | ||
|
|
af82dd719e | ||
|
|
ecd3625a08 | ||
|
|
da8f599ccb | ||
|
|
aa3216e48d | ||
|
|
5f7148419f | ||
|
|
89ae106ea7 | ||
|
|
721a7d9e4e | ||
|
|
18f2746f0d | ||
|
|
8a10f2191f | ||
|
|
8b3c8d15c4 | ||
|
|
49ca9364f7 | ||
|
|
62f6429b60 | ||
|
|
b6a9836e81 | ||
|
|
be34d8abf4 | ||
|
|
9af15d7ab3 | ||
|
|
308fef2859 | ||
|
|
3cc0c80b1e | ||
|
|
cdda33a98e | ||
|
|
e57a4332ec | ||
|
|
e88e553cc9 | ||
|
|
a1a38d0d7c | ||
|
|
c9bebd6550 | ||
|
|
42047070dd | ||
|
|
316f3bd963 | ||
|
|
5f96e646d4 | ||
|
|
186114996c | ||
|
|
841b6e85ae | ||
|
|
7ac9853cf6 | ||
|
|
0ec45b9da6 | ||
|
|
dfd0fe9fe4 | ||
|
|
4710268e0a | ||
|
|
cae512e4de | ||
|
|
6351d4c5a4 | ||
|
|
1173bb4f34 | ||
|
|
e4272b5337 | ||
|
|
b660506e31 | ||
|
|
2c101aef08 | ||
|
|
498b2a4f81 | ||
|
|
a8c2fd420a | ||
|
|
dade7fdc76 | ||
|
|
1c8b16f798 | ||
|
|
89649d8777 | ||
|
|
9894bf875b | ||
|
|
45a800330b | ||
|
|
a35e5f929d | ||
|
|
9a3f10d4bf | ||
|
|
19b5f921a1 | ||
|
|
8cd577904e | ||
|
|
309d661bcc | ||
|
|
8736024d9b | ||
|
|
97680e57a8 | ||
|
|
638522600a | ||
|
|
081113a62c | ||
|
|
7535c84581 | ||
|
|
690f3a2ead | ||
|
|
88371d08b9 | ||
|
|
6d382450cf | ||
|
|
19f2a6f282 | ||
|
|
7ed0b016ea | ||
|
|
f72a51e13d | ||
|
|
0e2dbbe754 | ||
|
|
cff51a0425 | ||
|
|
7cac4bbbab | ||
|
|
3f4a46bca6 | ||
|
|
7d21a75ea8 | ||
|
|
88817b7093 | ||
|
|
52cdadc035 | ||
|
|
5401b9b227 | ||
|
|
38de930f81 | ||
|
|
9be6ef7ba6 | ||
|
|
739bc6e26c | ||
|
|
71879266ac | ||
|
|
5ced0a1d4b | ||
|
|
908e361985 | ||
|
|
797affae4d | ||
|
|
ae3b825e29 | ||
|
|
143d97a73b | ||
|
|
90631c54b1 | ||
|
|
478e2998a8 | ||
|
|
9406305b2e | ||
|
|
1c26c81b20 | ||
|
|
a455de88b0 | ||
|
|
fba6942d5f | ||
|
|
3115efb672 | ||
|
|
fd70c031cb | ||
|
|
a2eb75df68 | ||
|
|
4a62d7eba6 | ||
|
|
40d2d2fe06 | ||
|
|
d5d2cb5937 | ||
|
|
854100c075 | ||
|
|
5837b26208 | ||
|
|
da0e654e7d | ||
|
|
a3e9932be7 | ||
|
|
e82353b4d9 | ||
|
|
944b61f28c | ||
|
|
457c574865 | ||
|
|
089a509663 | ||
|
|
3bebaef969 | ||
|
|
37e8b4500e | ||
|
|
8537ddf8a6 | ||
|
|
346b1e0a6b | ||
|
|
fc7b9660a5 | ||
|
|
21e5cc22c7 | ||
|
|
3f18b37e5f | ||
|
|
5d4a90e9bd | ||
|
|
2bf9f4f062 | ||
|
|
d69490cb49 | ||
|
|
4e460c11ca | ||
|
|
9313969314 | ||
|
|
a40f89a922 | ||
|
|
e0d8410b62 | ||
|
|
bef1bd8ad1 | ||
|
|
81b4fcfac1 | ||
|
|
f1e4a3c65d | ||
|
|
65622b01f6 | ||
|
|
87dd5f13fd | ||
|
|
79cd2c17ba | ||
|
|
85fb08552e | ||
|
|
7bd4b6faf7 | ||
|
|
0b1ae7e295 | ||
|
|
35a893ad9e | ||
|
|
4955ed18f1 | ||
|
|
fe462328ab | ||
|
|
5136d92efa | ||
|
|
227f7872cb | ||
|
|
725b2fdc35 | ||
|
|
75abc8059f | ||
|
|
f1193743c8 | ||
|
|
109730eacd | ||
|
|
1f736afe86 | ||
|
|
4d554a6718 | ||
|
|
69c0c362e9 | ||
|
|
3bb446556a | ||
|
|
ea950d8cec | ||
|
|
a65f4da7a2 | ||
|
|
0bdc933c20 | ||
|
|
0c0f79c6db | ||
|
|
32f9b9d4ac | ||
|
|
53907a3719 | ||
|
|
4937aeee3f | ||
|
|
5e5b8aff89 | ||
|
|
a2cbbd82d0 | ||
|
|
7eac5d8ba8 | ||
|
|
e2b1ed55ae | ||
|
|
727c7102d3 | ||
|
|
1494ea6717 | ||
|
|
f1ce64dbd3 | ||
|
|
3bad5cd2bf | ||
|
|
7432c0073a | ||
|
|
f1813a7c94 | ||
|
|
9e45c0a4d1 | ||
|
|
2c652cdde7 | ||
|
|
7718d345c8 | ||
|
|
9f39708325 | ||
|
|
bb6dbfa920 | ||
|
|
ba265005bb | ||
|
|
4d7cc7ed61 | ||
|
|
b64f31eb0b | ||
|
|
38d159b69e | ||
|
|
d5455f3716 | ||
|
|
a72ceeba11 | ||
|
|
c6b7d332b2 | ||
|
|
f37278f2a6 | ||
|
|
3f3e03b83d | ||
|
|
c99d3eb3c3 | ||
|
|
08d5183e7e | ||
|
|
51769b2224 | ||
|
|
6ec0ed8d61 | ||
|
|
2e35324403 | ||
|
|
e9474649c4 | ||
|
|
a8e0ce50c8 | ||
|
|
db7ddba735 | ||
|
|
1999d94b33 | ||
|
|
44af123b6c | ||
|
|
547b700ba7 | ||
|
|
6b87d5d2b0 | ||
|
|
023894d45e | ||
|
|
009715c0da | ||
|
|
c2824027d4 | ||
|
|
65b6553a1a | ||
|
|
9d3b7adc8e | ||
|
|
3724fc204c | ||
|
|
b97451a915 | ||
|
|
9ddcac4c6c | ||
|
|
b61e3c347f | ||
|
|
0bb44066c0 | ||
|
|
305c4aaa07 | ||
|
|
42d627f3ba | ||
|
|
6dd2b464a3 | ||
|
|
32f24cf8f8 | ||
|
|
4a89e3ea86 | ||
|
|
887db5b281 | ||
|
|
fee5518a82 | ||
|
|
551128e64c | ||
|
|
c65ae8d18e | ||
|
|
c1f75d9ebd | ||
|
|
73a5ff6648 | ||
|
|
1c264f380e | ||
|
|
f02bfa0a1e | ||
|
|
9d684006fc | ||
|
|
c49f1ed028 | ||
|
|
d935b226c0 | ||
|
|
d9e20de8a5 | ||
|
|
23997f0f93 | ||
|
|
529272d11b | ||
|
|
1194c38568 | ||
|
|
f0d2ee2beb | ||
|
|
68cdda086a | ||
|
|
54ceca6ceb | ||
|
|
50bdf7460c | ||
|
|
c06e45d0bb | ||
|
|
3ed6e28a00 | ||
|
|
ab76098895 | ||
|
|
0a447e43b0 | ||
|
|
8df44f2768 | ||
|
|
a7ec64d644 | ||
|
|
868e104d85 | ||
|
|
7ced7f5764 | ||
|
|
12b39c6ba1 | ||
|
|
93df9d7693 | ||
|
|
3980f314fa | ||
|
|
c2538da1cd | ||
|
|
5ed943bca2 | ||
|
|
d6a0563319 | ||
|
|
af82a94b87 | ||
|
|
82219e6111 | ||
|
|
81f9c55c7f | ||
|
|
0640f278cc | ||
|
|
769b5c6bab | ||
|
|
bdd569e213 | ||
|
|
5bfff5bc24 | ||
|
|
edf32496e4 | ||
|
|
785f5837d1 | ||
|
|
8c9272bc9f | ||
|
|
3e00735b3d | ||
|
|
00a1be8666 | ||
|
|
a2783d3c8a | ||
|
|
85d1a8a4a4 |
88
.github/workflows/build-debug.yml
vendored
88
.github/workflows/build-debug.yml
vendored
@@ -3,72 +3,76 @@ name: Build-Debug
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "**"
|
||||
tags:
|
||||
- "!*" # not a tag push
|
||||
- "master"
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
build-dotnet:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
NUGET_XMLDOC_MODE: skip
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-dotnet@v1
|
||||
- uses: actions/checkout@v3
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
with:
|
||||
dotnet-version: 3.1.101
|
||||
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
|
||||
dotnet-version: |
|
||||
3.1.x
|
||||
6.0.x
|
||||
- run: dotnet build -c Debug
|
||||
- run: dotnet test -c Debug
|
||||
|
||||
build-unity:
|
||||
if: "(github.event == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')"
|
||||
if: "((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ["2019.3.9f1", "2020.1.0b5"]
|
||||
unity: ["2019.3.9f1", "2019.4.13f1", "2020.1.12f1"]
|
||||
include:
|
||||
- unity: 2019.3.9f1
|
||||
license: UNITY_2019_3
|
||||
- unity: 2020.1.0b5
|
||||
license: UNITY_2020_1
|
||||
license: UNITY_LICENSE_2019
|
||||
- unity: 2019.4.13f1
|
||||
license: UNITY_LICENSE_2019
|
||||
- unity: 2020.1.12f1
|
||||
license: UNITY_LICENSE_2020
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags
|
||||
image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- run: apt update && apt install git -y
|
||||
- uses: actions/checkout@v2
|
||||
# create unity activation file and store to artifacts.
|
||||
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile || exit 0
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Unity_v${{ matrix.unity }}.alf
|
||||
path: ./Unity_v${{ matrix.unity }}.alf
|
||||
# activate Unity from manual license file(ulf)
|
||||
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
|
||||
- uses: actions/checkout@v3
|
||||
# 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: game-ci/unity-builder@v2
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
- name: Activate Unity, always returns a success. But if a subsequent run fails, the activation may have failed(if succeeded, shows `Next license update check is after` and not shows other message(like GUID != GUID). If fails not). In that case, upload the artifact's .alf file to https://license.unity3d.com/manual to get the .ulf file and set it to secrets.
|
||||
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -manualLicenseFile .Unity.ulf || exit 0
|
||||
|
||||
# Execute scripts: RuntimeUnitTestToolkit
|
||||
- name: Build UnitTest(Linux64, mono)
|
||||
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend mono /BuildTarget StandaloneLinux64
|
||||
working-directory: src/UniTask
|
||||
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: Export unitypackage
|
||||
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
working-directory: src/UniTask
|
||||
uses: game-ci/unity-builder@v2
|
||||
env:
|
||||
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
|
||||
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UniTask.unitypackage.zip
|
||||
name: UniTask.unitypackage-${{ matrix.unity }}.zip
|
||||
path: ./src/UniTask/*.unitypackage
|
||||
|
||||
8
.github/workflows/build-docs.yml
vendored
8
.github/workflows/build-docs.yml
vendored
@@ -8,11 +8,11 @@ on:
|
||||
|
||||
jobs:
|
||||
run-docfx:
|
||||
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Cysharp/DocfxTemplate
|
||||
path: docs/_DocfxTemplate
|
||||
@@ -28,4 +28,4 @@ jobs:
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: docs/_site
|
||||
publish_dir: docs/_site
|
||||
|
||||
167
.github/workflows/build-release.yml
vendored
167
.github/workflows/build-release.yml
vendored
@@ -1,105 +1,126 @@
|
||||
name: Build-Release
|
||||
name: build-release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+.[0-9]+*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "tag: git tag you want create. (sample 1.0.0)"
|
||||
required: true
|
||||
dry-run:
|
||||
description: "dry-run: true will never create relase/nuget."
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
DRY_RUN: ${{ github.event.inputs.dry-run }}
|
||||
|
||||
jobs:
|
||||
build-dotnet:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
NUGET_XMLDOC_MODE: skip
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 3.1.101
|
||||
# set release tag(*.*.*) to env.GIT_TAG
|
||||
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/}
|
||||
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) }}
|
||||
|
||||
build-dotnet:
|
||||
needs: [update-packagejson]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
with:
|
||||
dotnet-version: |
|
||||
3.1.x
|
||||
6.0.x
|
||||
# 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 }}
|
||||
|
||||
- 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@v1
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: nuget
|
||||
path: ./src/UniTask.NetCore/bin/Release/UniTask.${{ env.GIT_TAG }}.nupkg
|
||||
path: ./publish/
|
||||
|
||||
build-unity:
|
||||
needs: [update-packagejson]
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ['2019.3.9f1']
|
||||
unity: ["2019.3.9f1"]
|
||||
include:
|
||||
- unity: 2019.3.9f1
|
||||
license: UNITY_2019_3
|
||||
license: UNITY_LICENSE_2019
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# with linux-il2cpp. image from https://hub.docker.com/r/gableroux/unity3d/tags
|
||||
image: gableroux/unity3d:${{ matrix.unity }}-linux-il2cpp
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- run: apt update && apt install git -y
|
||||
- uses: actions/checkout@v2
|
||||
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/checkout@v3
|
||||
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: Export unitypackage
|
||||
uses: game-ci/unity-builder@v2
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -manualLicenseFile .Unity.ulf || exit 0
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
versioning: None
|
||||
|
||||
# set release tag(*.*.*) to env.GIT_TAG
|
||||
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/}
|
||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
||||
with:
|
||||
directory: src/UniTask
|
||||
|
||||
# Execute scripts: Export Package
|
||||
- name: Export unitypackage
|
||||
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
working-directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
|
||||
create-release:
|
||||
needs: [build-dotnet, build-unity]
|
||||
if: github.event.inputs.dry-run == 'false'
|
||||
needs: [update-packagejson, build-dotnet, build-unity]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
NUGET_XMLDOC_MODE: skip
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
# setup dotnet for nuget push
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 3.1.101
|
||||
# set release tag(*.*.*) to env.GIT_TAG
|
||||
- run: echo ::set-env name=GIT_TAG::${GITHUB_REF#refs/tags/}
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
# Create Releases
|
||||
- uses: actions/create-release@v1
|
||||
id: create_release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ env.GIT_TAG }}
|
||||
release_name: Ver.${{ env.GIT_TAG }}
|
||||
commitish: ${{ needs.update-packagejson.outputs.sha }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
# Download(All) Artifacts to current directory
|
||||
- uses: actions/download-artifact@v2
|
||||
# Upload to NuGet
|
||||
- run: dotnet nuget push "./nuget/*.nupkg" --skip-duplicate -s https://www.nuget.org/api/v2/package -k ${{ secrets.NUGET_KEY }}
|
||||
# Upload to Releases(unitypackage)
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./UniTask.${{ env.GIT_TAG }}.unitypackage/UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
asset_name: UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
# Create Releases
|
||||
- uses: actions/create-release@v1
|
||||
id: create_release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Ver.${{ github.ref }}
|
||||
|
||||
# Download(All) Artifacts to current directory
|
||||
- uses: actions/download-artifact@v2-preview
|
||||
|
||||
# Upload to NuGet
|
||||
- run: dotnet nuget push "./nuget/*.nupkg" -s https://www.nuget.org/api/v2/package -k ${{ secrets.NUGET_KEY }}
|
||||
|
||||
# Upload to Releases(unitypackage)
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./UniTask.${{ env.GIT_TAG }}.unitypackage/UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
asset_name: UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
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 }}
|
||||
|
||||
10
.github/workflows/stale.yml
vendored
Normal file
10
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
name: "Close stale issues"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main
|
||||
56
.gitignore
vendored
56
.gitignore
vendored
@@ -205,3 +205,59 @@ src/UniTask/UnityEngine.Monetization.csproj
|
||||
src/UniTask/UnityEngine.TestRunner.csproj
|
||||
|
||||
src/UniTask/UnityEngine.UI.csproj
|
||||
|
||||
src/UniTask/TempAsm.csproj
|
||||
|
||||
src/UniTask/UniTask.Addressables.csproj
|
||||
|
||||
src/UniTask/UniTask.DOTween.csproj
|
||||
|
||||
src/UniTask/UniTask.TextMeshPro.csproj
|
||||
|
||||
src/UniTask/RuntimeUnitTestToolkit.Player.csproj
|
||||
|
||||
src/UniTask/TempAsm.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.Addressables.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.DOTween.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.Linq.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.Tests.Player.csproj
|
||||
|
||||
src/UniTask/UniTask.TextMeshPro.Player.csproj
|
||||
|
||||
src/UniTask/Unity.Addressables.Player.csproj
|
||||
|
||||
src/UniTask/Unity.Analytics.DataPrivacy.Player.csproj
|
||||
|
||||
src/UniTask/Unity.ResourceManager.Player.csproj
|
||||
|
||||
src/UniTask/Unity.ScriptableBuildPipeline.Player.csproj
|
||||
|
||||
src/UniTask/Unity.TextMeshPro.Player.csproj
|
||||
|
||||
src/UniTask/Unity.Timeline.Player.csproj
|
||||
|
||||
src/UniTask/UnityEngine.Advertisements.Player.csproj
|
||||
|
||||
src/UniTask/UnityEngine.Monetization.Player.csproj
|
||||
|
||||
src/UniTask/UnityEngine.TestRunner.Player.csproj
|
||||
|
||||
src/UniTask/UnityEngine.UI.Player.csproj
|
||||
|
||||
src/UniTask/DOTween.Modules.Player.csproj
|
||||
|
||||
src/UniTask/Assembly-CSharp.Player.csproj
|
||||
|
||||
src/UniTask/Unity.EditorCoroutines.Editor.csproj
|
||||
|
||||
src/UniTask/.vsconfig
|
||||
|
||||
src/UniTask/Logs/ApiUpdaterCheck.txt
|
||||
|
||||
src/UniTask/Assembly-CSharp-firstpass.csproj
|
||||
|
||||
537
README.md
537
README.md
@@ -1,20 +1,21 @@
|
||||
UniTask
|
||||
===
|
||||
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
||||
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases) [](https://github.com/Cysharp/UniTask/blob/master/README_CN.md)
|
||||
|
||||
Provides an efficient allocation free async/await integration to Unity.
|
||||
Provides an efficient allocation free async/await integration for Unity.
|
||||
|
||||
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation
|
||||
* All Unity AsyncOperations and Coroutine to awaitable
|
||||
* PlayerLoop based task(`UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc..) that enable to replace all coroutine operation
|
||||
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achieve zero allocation
|
||||
* Makes all Unity AsyncOperations and Coroutines awaitable
|
||||
* PlayerLoop based task(`UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc..) that enable replacing all coroutine operations
|
||||
* MonoBehaviour Message Events and uGUI Events as awaitable/async-enumerable
|
||||
* Completely run on Unity's PlayerLoop so don't use thread and run on WebGL, wasm, etc.
|
||||
* Runs completely on Unity's PlayerLoop so doesn't use threads and runs on WebGL, wasm, etc.
|
||||
* Asynchronous LINQ, with Channel and AsyncReactiveProperty
|
||||
* TaskTracker window to prevent memory leak
|
||||
* TaskTracker window to prevent memory leaks
|
||||
* Highly compatible behaviour with Task/ValueTask/IValueTaskSource
|
||||
|
||||
Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ
|
||||
](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
||||
For technical details, see blog post: [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ
|
||||
](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
||||
For advanced tips, see blog post: [Extends UnityWebRequest via async decorator pattern — Advanced Techniques of UniTask](https://medium.com/@neuecc/extends-unitywebrequest-via-async-decorator-pattern-advanced-techniques-of-unitask-ceff9c5ee846)
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
@@ -23,6 +24,7 @@ Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await f
|
||||
- [Getting started](#getting-started)
|
||||
- [Basics of UniTask and AsyncOperation](#basics-of-unitask-and-asyncoperation)
|
||||
- [Cancellation and Exception handling](#cancellation-and-exception-handling)
|
||||
- [Timeout handling](#timeout-handling)
|
||||
- [Progress](#progress)
|
||||
- [PlayerLoop](#playerloop)
|
||||
- [async void vs async UniTaskVoid](#async-void-vs-async-unitaskvoid)
|
||||
@@ -32,8 +34,13 @@ Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await f
|
||||
- [Awaitable Events](#awaitable-events)
|
||||
- [Channel](#channel)
|
||||
- [For Unit Testing](#for-unit-testing)
|
||||
- [ThreadPool limitation](#threadpool-limitation)
|
||||
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
||||
- [For UnityEditor](#for-unityeditor)
|
||||
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||
- [Pooling Configuration](#pooling-configuration)
|
||||
- [Allocation on Profiler](#allocation-on-profiler)
|
||||
- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)
|
||||
- [API References](#api-references)
|
||||
- [UPM Package](#upm-package)
|
||||
- [Install via git URL](#install-via-git-url)
|
||||
@@ -66,7 +73,7 @@ async UniTask<string> DemoAsync()
|
||||
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
||||
var asset3 = await Resources.LoadAsync<TextAsset>("baz").ToUniTask(Progress.Create<float>(x => Debug.Log(x)));
|
||||
|
||||
// await frame-based operation like coroutine
|
||||
// await frame-based operation like a coroutine
|
||||
await UniTask.DelayFrame(100);
|
||||
|
||||
// replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
|
||||
@@ -79,8 +86,8 @@ async UniTask<string> DemoAsync()
|
||||
await UniTask.Yield();
|
||||
await UniTask.NextFrame();
|
||||
|
||||
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
|
||||
await UniTask.WaitForEndOfFrame();
|
||||
// replacement of WaitForEndOfFrame(requires MonoBehaviour(CoroutineRunner))
|
||||
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
|
||||
|
||||
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
|
||||
await UniTask.WaitForFixedUpdate();
|
||||
@@ -91,10 +98,10 @@ async UniTask<string> DemoAsync()
|
||||
// special helper of WaitUntil
|
||||
await UniTask.WaitUntilValueChanged(this, x => x.isActive);
|
||||
|
||||
// You can await IEnumerator coroutine
|
||||
// You can await IEnumerator coroutines
|
||||
await FooCoroutineEnumerator();
|
||||
|
||||
// You can await standard task
|
||||
// You can await a standard task
|
||||
await Task.Run(() => 100);
|
||||
|
||||
// Multithreading, run on ThreadPool under this code
|
||||
@@ -116,14 +123,11 @@ async UniTask<string> DemoAsync()
|
||||
var task2 = GetTextAsync(UnityWebRequest.Get("http://bing.com"));
|
||||
var task3 = GetTextAsync(UnityWebRequest.Get("http://yahoo.com"));
|
||||
|
||||
// concurrent async-wait and get result easily by tuple syntax
|
||||
// concurrent async-wait and get results easily by tuple syntax
|
||||
var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3);
|
||||
|
||||
// shorthand of WhenAll, tuple can await directly
|
||||
var (google2, bing2, yahoo2) = await (task1, task2, task3);
|
||||
|
||||
// You can handle timeout easily
|
||||
await GetTextAsync(UnityWebRequest.Get("http://unity.com")).Timeout(TimeSpan.FromMilliseconds(300));
|
||||
|
||||
// return async-value.(or you can use `UniTask`(no result), `UniTaskVoid`(fire and forget)).
|
||||
return (asset as TextAsset)?.text ?? throw new InvalidOperationException("Asset not found");
|
||||
@@ -132,11 +136,11 @@ async UniTask<string> DemoAsync()
|
||||
|
||||
Basics of UniTask and AsyncOperation
|
||||
---
|
||||
UniTask feature rely on C# 7.0([task-like custom async method builder feature](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)) so required Unity version is after `Unity 2018.3`, officialy lower support version is `Unity 2018.4.13f1`.
|
||||
UniTask features rely on C# 7.0([task-like custom async method builder feature](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)) so the required Unity version is after `Unity 2018.3`, the official lowest version supported is `Unity 2018.4.13f1`.
|
||||
|
||||
Why UniTask(custom task-like object) is required? Because Task is too heavy, not matched to Unity threading(single-thread). UniTask does not use thread and SynchronizationContext/ExecutionContext because almost Unity's asynchronous object is automaticaly dispatched by Unity's engine layer. It acquires more fast and more less allocation, completely integrated with Unity.
|
||||
Why is UniTask(custom task-like object) required? Because Task is too heavy and not matched to Unity threading (single-thread). UniTask does not use threads and SynchronizationContext/ExecutionContext because Unity's asynchronous object is automaticaly dispatched by Unity's engine layer. It achieves faster and lower allocation, and is completely integrated with Unity.
|
||||
|
||||
You can await `AsyncOperation`, `ResourceRequest`, `AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `IEnumerator` and others when `using Cysharp.Threading.Tasks;`.
|
||||
You can await `AsyncOperation`, `ResourceRequest`, `AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `AsyncGPUReadbackRequest`, `IEnumerator` and others when `using Cysharp.Threading.Tasks;`.
|
||||
|
||||
UniTask provides three pattern of extension methods.
|
||||
|
||||
@@ -146,33 +150,32 @@ UniTask provides three pattern of extension methods.
|
||||
* .ToUniTask(IProgress, PlayerLoopTiming, CancellationToken);
|
||||
```
|
||||
|
||||
`WithCancellation` is a simple version of `ToUniTask`, both returns `UniTask`. Details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
|
||||
`WithCancellation` is a simple version of `ToUniTask`, both return `UniTask`. For details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
|
||||
|
||||
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
|
||||
> Note: await directly is returned from native timing of PlayerLoop but WithCancellation and ToUniTask are returned from specified PlayerLoopTiming. For details of timing, see: [PlayerLoop](#playerloop) section.
|
||||
|
||||
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
||||
> Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
||||
|
||||
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.
|
||||
|
||||
```csharp
|
||||
public class SceneAssets
|
||||
public async UniTaskVoid LoadManyAsync()
|
||||
{
|
||||
public SceneAssets()
|
||||
{
|
||||
// parallel load.
|
||||
var (a, b, c) = await UniTask.WhenAll(
|
||||
LoadAsSprite("foo"),
|
||||
LoadAsSprite("bar"),
|
||||
LoadAsSprite("baz"));
|
||||
}
|
||||
// parallel load.
|
||||
var (a, b, c) = await UniTask.WhenAll(
|
||||
LoadAsSprite("foo"),
|
||||
LoadAsSprite("bar"),
|
||||
LoadAsSprite("baz"));
|
||||
}
|
||||
|
||||
async UniTask<Sprite> LoadAsSprite(string path)
|
||||
{
|
||||
var resource = await Resources.LoadAsync<Sprite>(path);
|
||||
return (resource as Sprite);
|
||||
}
|
||||
async UniTask<Sprite> LoadAsSprite(string path)
|
||||
{
|
||||
var resource = await Resources.LoadAsync<Sprite>(path);
|
||||
return (resource as Sprite);
|
||||
}
|
||||
```
|
||||
|
||||
If you want to convert callback to UniTask, you can use `UniTaskCompletionSource<T>` that is the lightweight edition of `TaskCompletionSource<T>`.
|
||||
If you want to convert a callback to UniTask, you can use `UniTaskCompletionSource<T>` which is a lightweight edition of `TaskCompletionSource<T>`.
|
||||
|
||||
```csharp
|
||||
public UniTask<int> WrapByUniTaskCompletionSource()
|
||||
@@ -189,7 +192,7 @@ public UniTask<int> WrapByUniTaskCompletionSource()
|
||||
|
||||
You can convert Task -> UniTask: `AsUniTask`, `UniTask` -> `UniTask<AsyncUnit>`: `AsAsyncUnitUniTask`, `UniTask<T>` -> `UniTask`: `AsUniTask`. `UniTask<T>` -> `UniTask`'s conversion cost is free.
|
||||
|
||||
If you want to convert async to coroutine, you can use `.ToCoroutine()`, this is useful to use only allow coroutine system.
|
||||
If you want to convert async to coroutine, you can use `.ToCoroutine()`, this is useful if you want to only allow using the coroutine system.
|
||||
|
||||
UniTask can not await twice. This is a similar constraint to the [ValueTask/IValueTaskSource](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=netcore-3.1) introduced in .NET Standard 2.1.
|
||||
|
||||
@@ -208,11 +211,13 @@ await task;
|
||||
await task; // NG, throws Exception
|
||||
```
|
||||
|
||||
Store to the class field, you can use `UniTask.Lazy` that gurantee call multipletimes. `.Prevent()` allows for multiple calls (internally cached results). This is useful when multiple calls in a function scope.
|
||||
Store to the class field, you can use `UniTask.Lazy` that supports calling multiple times. `.Preserve()` allows for multiple calls (internally cached results). This is useful when there are multiple calls in a function scope.
|
||||
|
||||
Also `UniTaskCompletionSource` can await multiple times and await from many callers.
|
||||
|
||||
Cancellation and Exception handling
|
||||
---
|
||||
Some UniTask factory methods have `CancellationToken cancellationToken = default` parameter. Andalso some async operation for unity have `WithCancellation(CancellationToken)` and `ToUniTask(..., CancellationToken cancellation = default)` extension methods.
|
||||
Some UniTask factory methods have a `CancellationToken cancellationToken = default` parameter. Also some async operations for Unity have `WithCancellation(CancellationToken)` and `ToUniTask(..., CancellationToken cancellation = default)` extension methods.
|
||||
|
||||
You can pass `CancellationToken` to parameter by standard [`CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource).
|
||||
|
||||
@@ -229,18 +234,66 @@ await UnityWebRequest.Get("http://google.co.jp").SendWebRequest().WithCancellati
|
||||
await UniTask.DelayFrame(1000, cancellationToken: cts.Token);
|
||||
```
|
||||
|
||||
CancellationToken can create by `CancellationTokenSource` or MonoBehaviour's extension method `GetCancellationTokenOnDestroy`.
|
||||
CancellationToken can be created by `CancellationTokenSource` or MonoBehaviour's extension method `GetCancellationTokenOnDestroy`.
|
||||
|
||||
```csharp
|
||||
// this CancellationToken lifecycle is same as GameObject.
|
||||
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
|
||||
```
|
||||
|
||||
When detect cancellation, all methods throws `OperationCanceledException` and propagate to upstream. `OperationCanceledException` is special exception, if not handled this exception, finally it is propagated to `UniTaskScheduler.UnobservedTaskException`.
|
||||
For propagate Cancellation, all async method recommend to accept `CancellationToken cancellationToken` at last argument, and pass `CancellationToken` from root to end.
|
||||
|
||||
Default behaviour of received unhandled exception is write log as exception. Log level can change by `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to change custom beavhiour, set action to `UniTaskScheduler.UnobservedTaskException.`
|
||||
```csharp
|
||||
await FooAsync(this.GetCancellationTokenOnDestroy());
|
||||
|
||||
If you want to cancel behaviour in async UniTask method, throws `OperationCanceledException` manually.
|
||||
// ---
|
||||
|
||||
async UniTask FooAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await BarAsync(cancellationToken);
|
||||
}
|
||||
|
||||
async UniTask BarAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(3), cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
`CancellationToken` means lifecycle of async. You can hold your own lifecycle insteadof default CancellationTokenOnDestroy.
|
||||
|
||||
```csharp
|
||||
public class MyBehaviour : MonoBehaviour
|
||||
{
|
||||
CancellationTokenSource disableCancellation = new CancellationTokenSource();
|
||||
CancellationTokenSource destroyCancellation = new CancellationTokenSource();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (disableCancellation != null)
|
||||
{
|
||||
disableCancellation.Dispose();
|
||||
}
|
||||
disableCancellation = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
disableCancellation.Cancel();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
destroyCancellation.Cancel();
|
||||
destroyCancellation.Dispose();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.`
|
||||
|
||||
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.
|
||||
|
||||
```csharp
|
||||
public async UniTask<int> FooAsync()
|
||||
@@ -250,7 +303,7 @@ public async UniTask<int> FooAsync()
|
||||
}
|
||||
```
|
||||
|
||||
If you handle exception but want to ignore(propagete to global cancellation handling), use exception filter.
|
||||
If you handle an exception but want to ignore(propagate to global cancellation handling), use an exception filter.
|
||||
|
||||
```csharp
|
||||
public async UniTask<int> BarAsync()
|
||||
@@ -260,14 +313,14 @@ public async UniTask<int> BarAsync()
|
||||
var x = await FooAsync();
|
||||
return x * 2;
|
||||
}
|
||||
catch (Exception ex) when (!(ex is OperationCanceledException))
|
||||
catch (Exception ex) when (!(ex is OperationCanceledException)) // when (ex is not OperationCanceledException) at C# 9.0
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
throws/catch `OperationCanceledException` is slightly heavy, if you want to care performance, use `UniTask.SuppressCancellationThrow` to avoid OperationCanceledException throw. It returns `(bool IsCanceled, T Result)` instead of throw.
|
||||
throws/catch `OperationCanceledException` is slightly heavy, so if performance is a concern, use `UniTask.SuppressCancellationThrow` to avoid OperationCanceledException throw. It returns `(bool IsCanceled, T Result)` instead of throwing.
|
||||
|
||||
```csharp
|
||||
var (isCanceled, _) = await UniTask.DelayFrame(10, cancellationToken: cts.Token).SuppressCancellationThrow();
|
||||
@@ -277,11 +330,105 @@ if (isCanceled)
|
||||
}
|
||||
```
|
||||
|
||||
Note: Only suppress throws if you call it directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not be suppressed throws.
|
||||
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.
|
||||
|
||||
Timeout handling
|
||||
---
|
||||
Timeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.
|
||||
|
||||
```csharp
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
|
||||
|
||||
try
|
||||
{
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(cts.Token);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (ex.CancellationToken == cts.Token)
|
||||
{
|
||||
UnityEngine.Debug.Log("Timeout");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `CancellationTokenSouce.CancelAfter` is a standard api. However in Unity you should not use it because it depends threading timer. `CancelAfterSlim` is UniTask's extension methods, it uses PlayerLoop instead.
|
||||
|
||||
If you want to use timeout with other source of cancellation, use `CancellationTokenSource.CreateLinkedTokenSource`.
|
||||
|
||||
```csharp
|
||||
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.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Optimize for reduce allocation of CancellationTokenSource for timeout per call async method, you can use UniTask's `TimeoutController`.
|
||||
|
||||
```csharp
|
||||
TimeoutController timeoutController = new TimeoutController(); // setup to field for reuse.
|
||||
|
||||
async UniTask FooAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// you can pass timeoutController.Timeout(TimeSpan) to cancellationToken.
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest()
|
||||
.WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5)));
|
||||
timeoutController.Reset(); // call Reset(Stop timeout timer and ready for reuse) when succeed.
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (timeoutController.IsTimeout())
|
||||
{
|
||||
UnityEngine.Debug.Log("timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to use timeout with other source of cancellation, use `new TimeoutController(CancellationToken)`.
|
||||
|
||||
```csharp
|
||||
TimeoutController timeoutController;
|
||||
CancellationTokenSource clickCancelSource;
|
||||
|
||||
void Start()
|
||||
{
|
||||
this.clickCancelSource = new CancellationTokenSource();
|
||||
this.timeoutController = new TimeoutController(clickCancelSource);
|
||||
}
|
||||
```
|
||||
|
||||
Note: UniTask has `.Timeout`, `.TimeoutWithoutException` methods however, if possible, do not use these, please pass `CancellationToken`. Because `.Timeout` work from external of task, can not stop timeoutted task. `.Timeout` means ignore result when timeout. If you pass a `CancellationToken` to the method, it will act from inside of the task, so it is possible to stop a running task.
|
||||
|
||||
Progress
|
||||
---
|
||||
Some async operation for unity have `ToUniTask(IProgress<float> progress = null, ...)` extension methods.
|
||||
Some async operations for unity have `ToUniTask(IProgress<float> progress = null, ...)` extension methods.
|
||||
|
||||
```csharp
|
||||
var progress = Progress.Create<float>(x => Debug.Log(x));
|
||||
@@ -291,9 +438,9 @@ var request = await UnityWebRequest.Get("http://google.co.jp")
|
||||
.ToUniTask(progress: progress);
|
||||
```
|
||||
|
||||
You should not use standard `new System.Progress<T>`, because it causes allocation every times. Use `Cysharp.Threading.Tasks.Progress` instead. This progress factory has two methods, `Create` and `CreateOnlyValueChanged`. `CreateOnlyValueChanged` calls only when progress value changed.
|
||||
You should not use standard `new System.Progress<T>`, because it causes allocation every time. Use `Cysharp.Threading.Tasks.Progress` instead. This progress factory has two methods, `Create` and `CreateOnlyValueChanged`. `CreateOnlyValueChanged` calls only when the progress value has changed.
|
||||
|
||||
Implements IProgress interface to caller is more better, there is no allocation of lambda.
|
||||
Implementing IProgress interface to caller is better as there is no lambda allocation.
|
||||
|
||||
```csharp
|
||||
public class Foo : MonoBehaviour, IProgress<float>
|
||||
@@ -314,7 +461,7 @@ public class Foo : MonoBehaviour, IProgress<float>
|
||||
|
||||
PlayerLoop
|
||||
---
|
||||
UniTask is run on custom [PlayerLoop](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html). UniTask's playerloop based method(such as `Delay`, `DelayFrame`, `asyncOperation.ToUniTask`, etc...) accepts this `PlayerLoopTiming`.
|
||||
UniTask is run on a custom [PlayerLoop](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html). UniTask's playerloop based methods (such as `Delay`, `DelayFrame`, `asyncOperation.ToUniTask`, etc...) accept this `PlayerLoopTiming`.
|
||||
|
||||
```csharp
|
||||
public enum PlayerLoopTiming
|
||||
@@ -339,28 +486,35 @@ public enum PlayerLoopTiming
|
||||
|
||||
PostLateUpdate = 12,
|
||||
LastPostLateUpdate = 13
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
TimeUpdate = 14,
|
||||
LastTimeUpdate = 15,
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop.
|
||||
|
||||
`PlayerLoopTiming.Update` is similar as `yield return null` in coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine.
|
||||
`PlayerLoopTiming.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`.
|
||||
|
||||
`yield return null` and `UniTask.Yield` is similar but different. `yield return null` always return next frame but `UniTask.Yield` return next called, that is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` gurantees return next frame, this would be expected to behave exactly the same as `yield return null`.
|
||||
> `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()`.
|
||||
|
||||
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and faster.
|
||||
`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`.
|
||||
|
||||
AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene's `Start` called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and runs on YieldRunner. It is the most lightweight and fastest.
|
||||
|
||||
In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, causes different order of Start and continuation after await. so recommend not to use `LoadSceneAsync.ToUniTask`.
|
||||
`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 stacktrace, you can check where is running in playerloop.
|
||||
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 the stacktrace, you can check where it is running in playerloop.
|
||||
|
||||

|
||||
|
||||
In default, UniTask's PlayerLoop is initialized at `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`.
|
||||
By default, UniTask's PlayerLoop is initialized at `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`.
|
||||
|
||||
The order in which methods are called in BeforeSceneLoad is indeterminate, so if you want to use UniTask in other BeforeSceneLoad methods, you should try to initialize it before this.
|
||||
The order in which methods are called in BeforeSceneLoad is nondeterministic, so if you want to use UniTask in other BeforeSceneLoad methods, you should try to initialize it before this.
|
||||
|
||||
```csharp
|
||||
// AfterAssembliesLoaded is called before BeforeSceneLoad
|
||||
@@ -372,9 +526,9 @@ public static void InitUniTaskLoop()
|
||||
}
|
||||
```
|
||||
|
||||
If you import Unity's `Entities` package, that reset custom player loop to default at `BeforeSceneLoad` and inject ECS's loop. When Unity call ECS's inject method after UniTask's initialize method, UniTask will no longer work.
|
||||
If you import Unity's `Entities` package, that resets the custom player loop to default at `BeforeSceneLoad` and injects ECS's loop. When Unity calls ECS's inject method after UniTask's initialize method, UniTask will no longer work.
|
||||
|
||||
To solve this issue, you can re-initialize UniTask PlayerLoop after ECS initialized.
|
||||
To solve this issue, you can re-initialize the UniTask PlayerLoop after ECS is initialized.
|
||||
|
||||
```csharp
|
||||
// Get ECS Loop.
|
||||
@@ -384,9 +538,50 @@ var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
|
||||
PlayerLoopHelper.Initialize(ref playerLoop);
|
||||
```
|
||||
|
||||
You can diagnose whether UniTask's player loop is ready by calling `PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()`. And also `PlayerLoopHelper.DumpCurrentPlayerLoop` logs all current playerloops to console.
|
||||
|
||||
```csharp
|
||||
void Start()
|
||||
{
|
||||
UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||
PlayerLoopHelper.DumpCurrentPlayerLoop();
|
||||
}
|
||||
```
|
||||
|
||||
You can optimize loop cost slightly by remove unuse PlayerLoopTiming injection. You can call `PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)` on initialize.
|
||||
|
||||
```csharp
|
||||
var loop = PlayerLoop.GetCurrentPlayerLoop();
|
||||
PlayerLoopHelper.Initialize(ref loop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate
|
||||
```
|
||||
|
||||
`InjectPlayerLoopTimings` has three preset, `All` and `Standard`(All without last except LastPostLateUpdate), `Minimum`(`Update | FixedUpdate | LastPostLateUpdate`). Default is All and you can combine custom inject timings like `InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate`.
|
||||
|
||||
You can make error to use uninjected `PlayerLoopTiming` by [Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md). For example, you can setup `BannedSymbols.txt` like this for `InjectPlayerLoopTimings.Minimum`.
|
||||
|
||||
```txt
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastInitialization; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.EarlyUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastEarlyUpdate; Isn't injected this PlayerLoop in this project.d
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastFixedUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PostLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.TimeUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.
|
||||
```
|
||||
|
||||
You can configure `RS0030` severity to error.
|
||||
|
||||

|
||||
|
||||
async void vs async UniTaskVoid
|
||||
---
|
||||
`async void` is a standard C# taks system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and report error immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
|
||||
`async void` is a standard C# task system so it does not run on UniTask systems. It is better not to use it. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and reports errors immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require awaiting (fire and forget), using `UniTaskVoid` is better. Unfortunately to dismiss warning, you're required to call `Forget()`.
|
||||
|
||||
```csharp
|
||||
public async UniTaskVoid FireAndForgetMethod()
|
||||
@@ -401,7 +596,7 @@ public void Caller()
|
||||
}
|
||||
```
|
||||
|
||||
Also UniTask have `Forget` method, it is similar with UniTaskVoid and same effects with it. However still UniTaskVoid is more efficient if completely do not use await。
|
||||
Also UniTask has the `Forget` method, it is similar to `UniTaskVoid` and has the same effects. However `UniTaskVoid` is more efficient if you completely don't use `await`。
|
||||
|
||||
```csharp
|
||||
public async UniTask DoAsync()
|
||||
@@ -416,7 +611,7 @@ public void Caller()
|
||||
}
|
||||
```
|
||||
|
||||
Using async lambda in register event, it is used `async void`. To avoid it, you can use `UniTask.Action` or `UniTask.UnityAction` that creates delegate via `async UniTaskVoid` lambda.
|
||||
To use an async lambda registered to an event, don't use `async void`. Instead you can use `UniTask.Action` or `UniTask.UnityAction`, both of which create a delegate via `async UniTaskVoid` lambda.
|
||||
|
||||
```csharp
|
||||
Action actEvent;
|
||||
@@ -431,9 +626,21 @@ actEvent += UniTask.Action(async () => { await UniTask.Yield(); });
|
||||
unityEvent += UniTask.UnityAction(async () => { await UniTask.Yield(); });
|
||||
```
|
||||
|
||||
`UniTaskVoid` can also be used in MonoBehaviour's `Start` method.
|
||||
|
||||
```csharp
|
||||
class Sample : MonoBehaviour
|
||||
{
|
||||
async UniTaskVoid Start()
|
||||
{
|
||||
// async init code.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
UniTaskTracker
|
||||
---
|
||||
useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
|
||||
useful for checking (leaked) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
|
||||
|
||||

|
||||
|
||||
@@ -443,13 +650,15 @@ useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTa
|
||||
* Enable Tracking(Toggle) - Start to track async/await UniTask. Performance impact: low.
|
||||
* Enable StackTrace(Toggle) - Capture StackTrace when task is started. Performance impact: high.
|
||||
|
||||
For debug use, enable tracking and capture stacktrace is useful but it it decline performance. Recommended usage is enable both to find task leak, and when done, finally disable both.
|
||||
UniTaskTracker is intended for debugging use only as enabling tracking and capturing stacktraces is useful but has a heavy performance impact. Recommended usage is to enable both tracking and stacktraces to find task leaks and to disable them both when done.
|
||||
|
||||
External Assets
|
||||
---
|
||||
In default, UniTask supports DOTween and Addressables(`AsyncOperationHandle` and `AsyncOpereationHandle<T>` as awaitable).
|
||||
By default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField` event extensions like standard uGUI `InputField`), DOTween(`Tween` as awaitable) and Addressables(`AsyncOperationHandle` and `AsyncOperationHandle<T>` as awaitable).
|
||||
|
||||
For DOTween support, require to `com.demigiant.dotween` import from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or define `UNITASK_DOTWEEN_SUPPORT` to enable it.
|
||||
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, 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
|
||||
@@ -464,12 +673,14 @@ await UniTask.WhenAll(
|
||||
transform.DOScale(10, 3).WithCancellation(ct));
|
||||
```
|
||||
|
||||
DOTween support's default behaviour(`await`, `WithCancellation`, `ToUniTask`) awaits tween is killed. It works on both Complete(true/false) and Kill(true/false). But if you want to reuse tweens (`SetAutoKill(false)`), it does not work as expected. If you want to await for another timing, the following extension methods exist in Tween, `AwaitForComplete`, `AwaitForPause`, `AwaitForPlay`, `AwaitForRewind`, `AwaitForStepComplete`.
|
||||
|
||||
AsyncEnumerable and Async LINQ
|
||||
---
|
||||
Unity 2020.2.0a12 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in async era.
|
||||
Unity 2020.2 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in the async era.
|
||||
|
||||
```csharp
|
||||
// Unity 2020.2.0a12, C# 8.0
|
||||
// Unity 2020.2, C# 8.0
|
||||
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate(token))
|
||||
{
|
||||
Debug.Log("Update() " + Time.frameCount);
|
||||
@@ -494,11 +705,19 @@ await okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).ForEachAsy
|
||||
});
|
||||
```
|
||||
|
||||
Fire and Forget style(for example, event handling), you can also use `Subscribe`.
|
||||
|
||||
```csharp
|
||||
okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).Subscribe(_ =>
|
||||
{
|
||||
});
|
||||
```
|
||||
|
||||
Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAsyncEnumerable` is defined in `UniTask.Linq` asmdef.
|
||||
|
||||
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 `Enumerbale`. 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`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`.
|
||||
`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`.
|
||||
|
||||
@@ -510,6 +729,38 @@ SelectAwaitWithCancellation(Func<T, CancellationToken, UniTask<TR>> selector)
|
||||
|
||||
If you want to use the `async` method inside the func, use the `***Await` or `***AwaitWithCancellation`.
|
||||
|
||||
How to create an async iterator: C# 8.0 supports async iterator(`async yield return`) but it only allows `IAsyncEnumerable<T>` and of course requires C# 8.0. UniTask supports `UniTaskAsyncEnumerable.Create` method to create custom async iterator.
|
||||
|
||||
```csharp
|
||||
// IAsyncEnumerable, C# 8.0 version of async iterator. ( do not use this style, IAsyncEnumerable is not controled in UniTask).
|
||||
public async IAsyncEnumerable<int> MyEveryUpdate([EnumeratorCancellation]CancellationToken cancelationToken = default)
|
||||
{
|
||||
var frameCount = 0;
|
||||
await UniTask.Yield();
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
yield return frameCount++;
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
// UniTaskAsyncEnumerable.Create and use `await writer.YieldAsync` instead of `yield return`.
|
||||
public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
||||
{
|
||||
// writer(IAsyncWriter<T>) has `YieldAsync(value)` method.
|
||||
return UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
var frameCount = 0;
|
||||
await UniTask.Yield();
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await writer.YieldAsync(frameCount++); // instead of `yield return`
|
||||
await UniTask.Yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Awaitable Events
|
||||
---
|
||||
All uGUI component implements `***AsAsyncEnumerable` to convert asynchronous streams of events.
|
||||
@@ -554,32 +805,13 @@ async UniTask TripleClick(CancellationToken token)
|
||||
}
|
||||
```
|
||||
|
||||
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can enable by `using Cysharp.Threading.Tasks.Triggers;`.
|
||||
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.
|
||||
|
||||
```csharp
|
||||
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 as uGUI event, AsyncTrigger can get by `GetAsync***Trigger` and trigger it self is UniTaskAsyncEnumerable.
|
||||
|
||||
```csharp
|
||||
// use await multiple times, get AsyncTriggerHandler is more efficient.
|
||||
using(var trigger = this.GetOnCollisionEnterAsyncHandler())
|
||||
{
|
||||
await OnCollisionEnterAsync();
|
||||
await OnCollisionEnterAsync();
|
||||
await OnCollisionEnterAsync();
|
||||
}
|
||||
var trigger = this.GetOnCollisionEnterAsyncHandler();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
|
||||
// every moves.
|
||||
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
||||
@@ -587,7 +819,7 @@ await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
||||
});
|
||||
```
|
||||
|
||||
`AsyncReactiveProperty`, `AsyncReadOnlyReactiveProperty` is UniTask version of UniTask's ReactiveProperty. `BindTo` extension method of `IUniTaskAsyncEnumerable<T>` for binding asynchronous stream values to Unity components(Text/Selectable/TMP/Text).
|
||||
`AsyncReactiveProperty`, `AsyncReadOnlyReactiveProperty` is UniTask's version of ReactiveProperty. `BindTo` extension method of `IUniTaskAsyncEnumerable<T>` for binding asynchronous stream values to Unity components(Text/Selectable/TMP/Text).
|
||||
|
||||
```csharp
|
||||
var rp = new AsyncReactiveProperty<int>(99);
|
||||
@@ -607,42 +839,51 @@ rp.WithoutCurrent().BindTo(this.textComponent);
|
||||
|
||||
await rp.WaitAsync(); // wait until next value set
|
||||
|
||||
// also exists ToReadOnlyReactiveProperty
|
||||
// also exists ToReadOnlyAsyncReactiveProperty
|
||||
var rp2 = new AsyncReactiveProperty<int>(99);
|
||||
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyReactiveProperty();
|
||||
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```csharp
|
||||
// can not get click event during 3 seconds complete.
|
||||
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync()
|
||||
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync(async x =>
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
It is useful(prevent double-click) but not useful in sometimes.
|
||||
It is useful (prevent double-click) but not useful sometimes.
|
||||
|
||||
Using `Queue()` method, which will also queue events during asynchronous processing.
|
||||
Using the `Queue()` method will also queue events during asynchronous processing.
|
||||
|
||||
```csharp
|
||||
// queued message in asynchronous processing
|
||||
await button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync()
|
||||
await button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync(async x =>
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Or use `Subscribe`, fire and forget style.
|
||||
|
||||
```csharp
|
||||
button.OnClickAsAsyncEnumerable().Subscribe(async x =>
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
||||
});
|
||||
```
|
||||
|
||||
Channel
|
||||
---
|
||||
`Channel` is same as [System.Threading.Tasks.Channels](https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.channels?view=netcore-3.1) that is similar as GoLang Channel.
|
||||
`Channel` is the same as [System.Threading.Tasks.Channels](https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels?view=netcore-3.1) which is similar to a GoLang Channel.
|
||||
|
||||
Currently only supports multiple-producer, single-consumer unbounded channel. It can create by `Channel.CreateSingleConsumerUnbounded<T>()`.
|
||||
Currently it only supports multiple-producer, single-consumer unbounded channels. It can create by `Channel.CreateSingleConsumerUnbounded<T>()`.
|
||||
|
||||
For producer(`.Writer`), `TryWrite` to push value and `TryComplete` to complete channel. For consumer(`.Reader`), `TryRead`, `WaitToReadAsync`, `ReadAsync`, `Completion` and `ReadAllAsync` to read queued messages.
|
||||
For producer(`.Writer`), use `TryWrite` to push value and `TryComplete` to complete channel. For consumer(`.Reader`), use `TryRead`, `WaitToReadAsync`, `ReadAsync`, `Completion` and `ReadAllAsync` to read queued messages.
|
||||
|
||||
`ReadAllAsync` returns `IUniTaskAsyncEnumerable<T>` so query LINQ operators. Reader only allows single-consumer but use `.Publish()` query operator to enable multicast message. For example, make pub/sub utility.
|
||||
`ReadAllAsync` returns `IUniTaskAsyncEnumerable<T>` so query LINQ operators. Reader only allows single-consumer but uses `.Publish()` query operator to enable multicast message. For example, make pub/sub utility.
|
||||
|
||||
```csharp
|
||||
public class AsyncMessageBroker<T> : IDisposable
|
||||
@@ -679,7 +920,7 @@ public class AsyncMessageBroker<T> : IDisposable
|
||||
|
||||
For Unit Testing
|
||||
---
|
||||
Unity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async method.
|
||||
Unity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async methods.
|
||||
|
||||
```csharp
|
||||
[UnityTest]
|
||||
@@ -702,11 +943,34 @@ public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
|
||||
});
|
||||
```
|
||||
|
||||
UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working.
|
||||
UniTask's own unit tests are written using Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to integrate with CI and check if IL2CPP is working.
|
||||
|
||||
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.
|
||||
|
||||
`UniTask.Run` is now deprecated. You can use `UniTask.RunOnThreadPool` instead. And also consider whether you can use `UniTask.Create` or `UniTask.Void`.
|
||||
|
||||
IEnumerator.ToUniTask limitation
|
||||
---
|
||||
You can convert coroutine(IEnumerator) to UniTask(or await directly) but it has some limitations.
|
||||
|
||||
* `WaitForEndOfFrame`/`WaitForFixedUpdate`/`Coroutine` is not supported.
|
||||
* Consuming loop timing is not the same as `StartCoroutine`, it uses the specified `PlayerLoopTiming` and the default `PlayerLoopTiming.Update` is run before MonoBehaviour's `Update` and `StartCoroutine`'s loop.
|
||||
|
||||
If you want fully compatible conversion from coroutine to async, use the `IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)` overload. It executes StartCoroutine on an instance of the argument MonoBehaviour and waits for it to complete in UniTask.
|
||||
|
||||
For UnityEditor
|
||||
---
|
||||
UniTask can run on Unity Editor like an Editor Coroutine. However, there are some limitations.
|
||||
|
||||
* UniTask.Delay's DelayType.DeltaTime, UnscaledDeltaTime do not work correctly because they can not get deltaTime in editor. Therefore run on EditMode, automatically change DelayType to `DelayType.Realtime` that wait for the right time.
|
||||
* All PlayerLoopTiming run on the timing `EditorApplication.update`.
|
||||
* `-batchmode` with `-quit` does not work because Unity does not run `EditorApplication.update` and quit after a single frame. Instead, don't use `-quit` and quit manually with `EditorApplication.Exit(0)`.
|
||||
|
||||
Compare with Standard Task API
|
||||
---
|
||||
UniTask has many standard Task-like APIs. This table shows what is the alternative apis.
|
||||
UniTask has many standard Task-like APIs. This table shows what the alternative apis are.
|
||||
|
||||
Use standard type.
|
||||
|
||||
@@ -740,7 +1004,7 @@ Use UniTask type.
|
||||
| `IAsyncDisposable` | `IUniTaskAsyncDisposable` |
|
||||
| `Task.Delay` | `UniTask.Delay` |
|
||||
| `Task.Yield` | `UniTask.Yield` |
|
||||
| `Task.Run` | `UniTask.Run` |
|
||||
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
||||
| `Task.WhenAll` | `UniTask.WhenAll` |
|
||||
| `Task.WhenAny` | `UniTask.WhenAny` |
|
||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||
@@ -752,7 +1016,7 @@ Use UniTask type.
|
||||
|
||||
Pooling Configuration
|
||||
---
|
||||
UniTask is aggressively caching async promise object to achive zero allocation. In default, cache all promises but you can configure `TaskPool.SetMaxPoolSize` to your value, the value indicates cache size per type. `TaskPool.GetCacheSizeInfo` returns current cached object in pool.
|
||||
UniTask aggressively caches async promise objects to achieve zero allocation (for technical details, see blog post [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)). By default, it caches all promises but you can configure `TaskPool.SetMaxPoolSize` to your value, the value indicates cache size per type. `TaskPool.GetCacheSizeInfo` returns currently cached objects in pool.
|
||||
|
||||
```csharp
|
||||
foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
||||
@@ -761,19 +1025,44 @@ foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
||||
}
|
||||
```
|
||||
|
||||
> In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build.
|
||||
Allocation on Profiler
|
||||
---
|
||||
In UnityEditor the profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generates AsyncStateMachine as class on Debug build and as struct on Release build.
|
||||
|
||||
Unity supports Code Optimization option starting in 2020.1 (right, footer).
|
||||
|
||||

|
||||
|
||||
You can change C# compiler optimization to release to remove AsyncStateMachine allocation in development builds. This optimization option can also be set via `Compilation.CompilationPipeline-codeOptimization`, and `Compilation.CodeOptimization`.
|
||||
|
||||
UniTaskSynchronizationContext
|
||||
---
|
||||
Unity's default SynchronizationContext(`UnitySynchronizationContext`) is a poor implementation for performance. UniTask bypasses `SynchronizationContext`(and `ExecutionContext`) so it does not use it but if exists in `async Task`, still used it. `UniTaskSynchronizationContext` is a replacement of `UnitySynchronizationContext` which is better for performance.
|
||||
|
||||
```csharp
|
||||
public class SyncContextInjecter
|
||||
{
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Inject()
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is an optional choice and is not always recommended; `UniTaskSynchronizationContext` is less performant than `async UniTask` and is not a complete UniTask replacement. It also does not guarantee full behavioral compatibility with the `UnitySynchronizationContext`.
|
||||
|
||||
API References
|
||||
---
|
||||
UniTask's API References is hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).
|
||||
UniTask's API References are hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).
|
||||
|
||||
For example, UniTask's factory methods can see at [UniTask#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.UniTask.html#methods-1). UniTaskAsyncEnumerable's factory/extension methods can see at [UniTaskAsyncEnumerable#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.Linq.UniTaskAsyncEnumerable.html#methods-1).
|
||||
For example, UniTask's factory methods can be seen at [UniTask#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.UniTask.html#methods-1). UniTaskAsyncEnumerable's factory/extension methods can be seen at [UniTaskAsyncEnumerable#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.Linq.UniTaskAsyncEnumerable.html#methods-1).
|
||||
|
||||
UPM Package
|
||||
---
|
||||
### Install via git URL
|
||||
|
||||
After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of git package. You can add `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask` to Package Manager
|
||||
Requires a version of unity that supports path query parameter for git packages (Unity >= 2019.3.4f1, Unity >= 2020.1a21). You can add `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask` to Package Manager
|
||||
|
||||

|
||||
|
||||
@@ -781,7 +1070,7 @@ After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of gi
|
||||
|
||||
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` to `Packages/manifest.json`.
|
||||
|
||||
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.15`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.15`.
|
||||
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
|
||||
|
||||
@@ -797,11 +1086,11 @@ For .NET Core, use NuGet.
|
||||
|
||||
> PM> Install-Package [UniTask](https://www.nuget.org/packages/UniTask)
|
||||
|
||||
UniTask of .NET Core version is a subset of Unity UniTask, removed PlayerLoop dependent methods.
|
||||
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. `AysncLocal` also does not work because it ignores ExecutionContext.
|
||||
|
||||
If you use UniTask internally, but provide ValueTask as an external API, you can write like the following(Inspired by [PooledAwait](https://github.com/mgravell/PooledAwait)).
|
||||
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)).
|
||||
|
||||
```csharp
|
||||
public class ZeroAllocAsyncAwaitInDotNetCore
|
||||
@@ -834,7 +1123,7 @@ public ValueTask TestAsync()
|
||||
|
||||
.NET Core version is intended to allow users to use UniTask as an interface when sharing code with Unity (such as [Cysharp/MagicOnion](https://github.com/Cysharp/MagicOnion/)). .NET Core version of UniTask enables smooth code sharing.
|
||||
|
||||
Utility methods such as WhenAll which is equivalent to UniTask are provided as [Cysharp/ValueTaskSupplement](https://github.com/Cysharp/ValueTaskSupplement).
|
||||
Utility methods such as WhenAll which are equivalent to UniTask are provided as [Cysharp/ValueTaskSupplement](https://github.com/Cysharp/ValueTaskSupplement).
|
||||
|
||||
License
|
||||
---
|
||||
|
||||
1133
README_CN.md
Normal file
1133
README_CN.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,15 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29613.14
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31606.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
|
||||
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}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -27,6 +29,10 @@ 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
|
||||
|
||||
8
src/UniTask.Analyzer/Properties/launchSettings.json
Normal file
8
src/UniTask.Analyzer/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"UniTask.Analyzer": {
|
||||
"commandName": "DebugRoslynComponent",
|
||||
"targetProject": "..\\UniTask.NetCoreSandbox\\UniTask.NetCoreSandbox.csproj"
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/UniTask.Analyzer/UniTask.Analyzer.csproj
Normal file
29
src/UniTask.Analyzer/UniTask.Analyzer.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<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>
|
||||
54
src/UniTask.Analyzer/UniTaskAnalyzer.cs
Normal file
54
src/UniTask.Analyzer/UniTaskAnalyzer.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/UniTask.NetCore/NetCore/AsyncEnumerableExtensions.cs
Normal file
101
src/UniTask.NetCore/NetCore/AsyncEnumerableExtensions.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
#if !NETSTANDARD2_0
|
||||
|
||||
#pragma warning disable 0649
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks.Sources;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class AsyncEnumerableExtensions
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> AsUniTaskAsyncEnumerable<T>(this IAsyncEnumerable<T> source)
|
||||
{
|
||||
return new AsyncEnumerableToUniTaskAsyncEnumerable<T>(source);
|
||||
}
|
||||
|
||||
public static IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IUniTaskAsyncEnumerable<T> source)
|
||||
{
|
||||
return new UniTaskAsyncEnumerableToAsyncEnumerable<T>(source);
|
||||
}
|
||||
|
||||
sealed class AsyncEnumerableToUniTaskAsyncEnumerable<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly IAsyncEnumerable<T> source;
|
||||
|
||||
public AsyncEnumerableToUniTaskAsyncEnumerable(IAsyncEnumerable<T> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
|
||||
}
|
||||
|
||||
sealed class Enumerator : IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
readonly IAsyncEnumerator<T> enumerator;
|
||||
|
||||
public Enumerator(IAsyncEnumerator<T> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public T Current => enumerator.Current;
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
await enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
public async UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
return await enumerator.MoveNextAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class UniTaskAsyncEnumerableToAsyncEnumerable<T> : IAsyncEnumerable<T>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<T> source;
|
||||
|
||||
public UniTaskAsyncEnumerableToAsyncEnumerable(IUniTaskAsyncEnumerable<T> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
|
||||
}
|
||||
|
||||
sealed class Enumerator : IAsyncEnumerator<T>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerator<T> enumerator;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public T Current => enumerator.Current;
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
public ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
return enumerator.MoveNextAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,15 +26,14 @@ namespace Cysharp.Threading.Tasks
|
||||
#endif
|
||||
}
|
||||
|
||||
public static UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true)
|
||||
public static async UniTask<T> AsUniTask<T>(this ValueTask<T> task)
|
||||
{
|
||||
// NOTE: get _obj and _token directly for low overhead conversion but not yet implemented.
|
||||
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||
return await task;
|
||||
}
|
||||
|
||||
public static UniTask AsUniTask(this ValueTask task, bool useCurrentSynchronizationContext = true)
|
||||
public static async UniTask AsUniTask(this ValueTask task)
|
||||
{
|
||||
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||
await task;
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||
{
|
||||
static TaskPool<ThreadPoolWorkItem> pool;
|
||||
public ThreadPoolWorkItem NextNode { get; set; }
|
||||
ThreadPoolWorkItem nextNode;
|
||||
public ref ThreadPoolWorkItem NextNode => ref nextNode;
|
||||
|
||||
static ThreadPoolWorkItem()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
<AssemblyName>UniTask</AssemblyName>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
|
||||
<!-- NuGet Packaging -->
|
||||
<Id>UniTask</Id>
|
||||
@@ -19,6 +21,9 @@
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageIcon>Icon.png</PackageIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>opensource.snk</AssemblyOriginatorKeyFile>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -26,29 +31,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs"
|
||||
Exclude="
|
||||
..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;
|
||||
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
|
||||
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
|
||||
" />
|
||||
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" Exclude="
..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopTimer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
" />
|
||||
<Compile Remove="..\UniTask\Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
BIN
src/UniTask.NetCore/opensource.snk
Normal file
BIN
src/UniTask.NetCore/opensource.snk
Normal file
Binary file not shown.
@@ -1,258 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
#pragma warning disable CS1998
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
using System.Linq;
|
||||
using System;
|
||||
@@ -15,509 +17,34 @@ using System.Reactive.Concurrency;
|
||||
|
||||
namespace NetCoreSandbox
|
||||
{
|
||||
public class MySyncContext : SynchronizationContext
|
||||
public class Program
|
||||
{
|
||||
public MySyncContext()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
|
||||
// OK.
|
||||
await FooAsync(10, cts.Token);
|
||||
|
||||
// NG(Compiler Error)
|
||||
// await FooAsync(10);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//await new AllocationCheck().ViaUniTaskVoid();
|
||||
//Console.ReadLine();
|
||||
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
|
||||
|
||||
//await new ComparisonBenchmarks().ViaUniTaskT();
|
||||
return;
|
||||
#endif
|
||||
// await new AllocationCheck().ViaUniTaskVoid();
|
||||
|
||||
// AsyncTest().Forge
|
||||
|
||||
Console.WriteLine("A?");
|
||||
var a = await new ZeroAllocAsyncAwaitInDotNetCore().NanikaAsync(1, 2);
|
||||
Console.WriteLine("RET:" + a);
|
||||
await WhereSelect();
|
||||
|
||||
SynchronizationContext.SetSynchronizationContext(new MySyncContext());
|
||||
|
||||
await Aaa();
|
||||
|
||||
|
||||
|
||||
|
||||
//AsyncTest().Forget();
|
||||
|
||||
// AsyncTest().Forget();
|
||||
|
||||
ThreadPool.SetMinThreads(100, 100);
|
||||
|
||||
//List<UniTask<int>> list = new List<UniTask<int>>();
|
||||
for (int i = 0; i < short.MaxValue; i++)
|
||||
{
|
||||
//// list.Add(AsyncTest());
|
||||
await YieldCore();
|
||||
}
|
||||
//await UniTask.WhenAll(list);
|
||||
|
||||
//Console.WriteLine("TOGO");
|
||||
|
||||
//var a = await AsyncTest();
|
||||
//var b = AsyncTest();
|
||||
//var c = AsyncTest();
|
||||
await YieldCore();
|
||||
|
||||
//await b;
|
||||
//await c;
|
||||
|
||||
|
||||
//foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPool.GetCacheSizeInfo())
|
||||
//{
|
||||
// Console.WriteLine(item);
|
||||
//}
|
||||
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
static async UniTask YieldCore()
|
||||
static async UniTask FooAsync(int x, CancellationToken cancellationToken = default)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
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();
|
||||
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 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 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; }
|
||||
}
|
||||
|
||||
// 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 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;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>NetCoreSandbox</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -15,6 +16,12 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
|
||||
|
||||
|
||||
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
167
src/UniTask.NetCoreTests/AsyncLazyTest.cs
Normal file
167
src/UniTask.NetCoreTests/AsyncLazyTest.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class AsyncLazyTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task LazyLazy()
|
||||
{
|
||||
{
|
||||
var l = UniTask.Lazy(() => After());
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await a;
|
||||
await b;
|
||||
await c;
|
||||
}
|
||||
{
|
||||
var l = UniTask.Lazy(() => AfterException());
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LazyImmediate()
|
||||
{
|
||||
{
|
||||
var l = UniTask.Lazy(() => UniTask.FromResult(1).AsUniTask());
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await a;
|
||||
await b;
|
||||
await c;
|
||||
}
|
||||
{
|
||||
var l = UniTask.Lazy(() => UniTask.FromException(new TaskTestException()));
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
|
||||
}
|
||||
}
|
||||
|
||||
static async UniTask AwaitAwait(UniTask t)
|
||||
{
|
||||
await t;
|
||||
}
|
||||
|
||||
|
||||
async UniTask After()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
await UniTask.Yield();
|
||||
await UniTask.Yield();
|
||||
}
|
||||
|
||||
async UniTask AfterException()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
await UniTask.Yield();
|
||||
throw new TaskTestException();
|
||||
}
|
||||
}
|
||||
|
||||
public class AsyncLazyTest2
|
||||
{
|
||||
[Fact]
|
||||
public async Task LazyLazy()
|
||||
{
|
||||
{
|
||||
var l = UniTask.Lazy(() => After());
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
var a2 = await a;
|
||||
var b2 = await b;
|
||||
var c2 = await c;
|
||||
(a2, b2, c2).Should().Be((10, 10, 10));
|
||||
}
|
||||
{
|
||||
var l = UniTask.Lazy(() => AfterException());
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LazyImmediate()
|
||||
{
|
||||
{
|
||||
var l = UniTask.Lazy(() => UniTask.FromResult(1));
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
var a2 = await a;
|
||||
var b2 = await b;
|
||||
var c2 = await c;
|
||||
(a2, b2, c2).Should().Be((1, 1, 1));
|
||||
}
|
||||
{
|
||||
var l = UniTask.Lazy(() => UniTask.FromException<int>(new TaskTestException()));
|
||||
var a = AwaitAwait(l.Task);
|
||||
var b = AwaitAwait(l.Task);
|
||||
var c = AwaitAwait(l.Task);
|
||||
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
|
||||
}
|
||||
}
|
||||
|
||||
static async UniTask<int> AwaitAwait(UniTask<int> t)
|
||||
{
|
||||
return await t;
|
||||
}
|
||||
|
||||
|
||||
async UniTask<int> After()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
await UniTask.Yield();
|
||||
await UniTask.Yield();
|
||||
return 10;
|
||||
}
|
||||
|
||||
async UniTask<int> AfterException()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
await UniTask.Yield();
|
||||
throw new TaskTestException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace NetCoreTests
|
||||
|
||||
var ar = await array;
|
||||
|
||||
ar.Should().BeEquivalentTo(new[] { 99, 100, 100, 100, 131 });
|
||||
ar.Should().Equal(new[] { 99, 100, 100, 100, 131 });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -49,7 +49,7 @@ namespace NetCoreTests
|
||||
|
||||
var ar = await array;
|
||||
|
||||
ar.Should().BeEquivalentTo(new[] { 100, 100, 100, 131, 191 });
|
||||
ar.Should().Equal(new[] { 100, 100, 100, 131, 191 });
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
@@ -70,7 +70,7 @@ namespace NetCoreTests
|
||||
|
||||
// var ar = await array;
|
||||
|
||||
// ar.Should().BeEquivalentTo(new[] { 99, 100, 100, 100, 131 });
|
||||
// ar.Should().Equal(new[] { 99, 100, 100, 100, 131 });
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
@@ -88,7 +88,7 @@ namespace NetCoreTests
|
||||
|
||||
// var ar = await array;
|
||||
|
||||
// ar.Should().BeEquivalentTo(new[] { 100, 100, 100, 131, 191 });
|
||||
// ar.Should().Equal(new[] { 100, 100, 100, 131, 191 });
|
||||
//}
|
||||
|
||||
|
||||
|
||||
@@ -276,8 +276,8 @@ namespace NetCoreTests
|
||||
reference.Writer.TryComplete();
|
||||
channel.Writer.TryComplete();
|
||||
|
||||
(await ta1).Should().BeEquivalentTo(new[] { 10, 20, 30 });
|
||||
(await ta2).Should().BeEquivalentTo(new[] { 10, 20, 30 });
|
||||
(await ta1).Should().Equal(new[] { 10, 20, 30 });
|
||||
(await ta2).Should().Equal(new[] { 10, 20, 30 });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
590
src/UniTask.NetCoreTests/CompletionSourceTest.cs
Normal file
590
src/UniTask.NetCoreTests/CompletionSourceTest.cs
Normal file
@@ -0,0 +1,590 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class CompletionSourceTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task SetFirst()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
tcs.TrySetResult();
|
||||
await tcs.Task; // ok.
|
||||
await tcs.Task; // ok.
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SingleOnFirst()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetResult();
|
||||
await a;
|
||||
await tcs.Task; // ok.
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiOne()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
tcs.TrySetResult();
|
||||
await a;
|
||||
await b;
|
||||
await tcs.Task; // ok.
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiTwo()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
tcs.TrySetResult();
|
||||
await a;
|
||||
await b;
|
||||
await c;
|
||||
await tcs.Task; // ok.
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await c);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
async UniTask Await()
|
||||
{
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
class TestException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class CompletionSourceTest2
|
||||
{
|
||||
[Fact]
|
||||
public async Task SetFirst()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
tcs.TrySetResult(10);
|
||||
var a = await tcs.Task; // ok.
|
||||
var b = await tcs.Task; // ok.
|
||||
a.Should().Be(10);
|
||||
b.Should().Be(10);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SingleOnFirst()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetResult(10);
|
||||
var r1 = await a;
|
||||
var r2 = await tcs.Task; // ok.
|
||||
r1.Should().Be(10);
|
||||
r2.Should().Be(10);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiOne()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
tcs.TrySetResult(10);
|
||||
var r1 = await a;
|
||||
var r2 = await b;
|
||||
var r3 = await tcs.Task; // ok.
|
||||
(r1, r2, r3).Should().Be((10, 10, 10));
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiTwo()
|
||||
{
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
tcs.TrySetResult(10);
|
||||
var r1 = await a;
|
||||
var r2 = await b;
|
||||
var r3 = await c;
|
||||
var r4 = await tcs.Task; // ok.
|
||||
(r1, r2, r3, r4).Should().Be((10, 10, 10, 10));
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
|
||||
}
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetException(new TestException());
|
||||
await Assert.ThrowsAsync<TestException>(async () => await a);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await b);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await c);
|
||||
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetException(new OperationCanceledException(cts.Token));
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<int>();
|
||||
|
||||
async UniTask<int> Await()
|
||||
{
|
||||
return await tcs.Task;
|
||||
}
|
||||
|
||||
var a = Await();
|
||||
var b = Await();
|
||||
var c = Await();
|
||||
|
||||
tcs.TrySetCanceled(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
|
||||
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
class TestException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,7 +481,7 @@ namespace NetCoreTests.Linq
|
||||
list.Add(x);
|
||||
});
|
||||
|
||||
list.Should().BeEquivalentTo(Enumerable.Range(1, 10));
|
||||
list.Should().Equal(Enumerable.Range(1, 10));
|
||||
|
||||
var list2 = new List<(int, int)>();
|
||||
await Enumerable.Range(5, 10).ToUniTaskAsyncEnumerable().ForEachAsync((index, x) =>
|
||||
@@ -490,7 +490,7 @@ namespace NetCoreTests.Linq
|
||||
});
|
||||
|
||||
var list3 = Enumerable.Range(5, 10).Select((index, x) => (index, x)).ToArray();
|
||||
list2.Should().BeEquivalentTo(list3);
|
||||
list2.Should().Equal(list3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Enumerable.Range(start, count).ToUniTaskAsyncEnumerable().Append(99).ToArrayAsync();
|
||||
var ys = Enumerable.Range(start, count).Append(99).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -50,7 +50,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Enumerable.Range(start, count).ToUniTaskAsyncEnumerable().Prepend(99).ToArrayAsync();
|
||||
var ys = Enumerable.Range(start, count).Prepend(99).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
|
||||
|
||||
var xs = await l.ToUniTaskAsyncEnumerable().Concat(r.ToUniTaskAsyncEnumerable()).ToArrayAsync();
|
||||
var ys = l.Concat(r).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -119,17 +119,17 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 0).ToUniTaskAsyncEnumerable().DefaultIfEmpty(99).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, 0).DefaultIfEmpty(99).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 1).ToUniTaskAsyncEnumerable().DefaultIfEmpty(99).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, 1).DefaultIfEmpty(99).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 10).ToUniTaskAsyncEnumerable().DefaultIfEmpty(99).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, 10).DefaultIfEmpty(99).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
// Throw
|
||||
{
|
||||
|
||||
@@ -34,11 +34,11 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, 10).ToObservable().ToArray();
|
||||
xs.Should().BeEquivalentTo(Enumerable.Range(1, 10));
|
||||
xs.Should().Equal(Enumerable.Range(1, 10));
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, 0).ToObservable().ToArray();
|
||||
xs.Should().BeEquivalentTo(Enumerable.Range(1, 0));
|
||||
xs.Should().Equal(Enumerable.Range(1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,21 +70,21 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Observable.Range(1, 100).ToUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
var ys = await Observable.Range(1, 100).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
{
|
||||
var xs = await Observable.Range(1, 100, ThreadPoolScheduler.Instance).ToUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
var ys = await Observable.Range(1, 100, ThreadPoolScheduler.Instance).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
{
|
||||
var xs = await Observable.Empty<int>(ThreadPoolScheduler.Instance).ToUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
var ys = await Observable.Empty<int>(ThreadPoolScheduler.Instance).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,25 +95,25 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Enumerable.Range(1, 100).ToUniTaskAsyncEnumerable().ToDictionaryAsync(x => x);
|
||||
var ys = Enumerable.Range(1, 100).ToDictionary(x => x);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.OrderBy(x => x.Key).Should().Equal(ys.OrderBy(x => x.Key));
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 0).ToUniTaskAsyncEnumerable().ToDictionaryAsync(x => x);
|
||||
var ys = Enumerable.Range(1, 0).ToDictionary(x => x);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.OrderBy(x => x.Key).Should().Equal(ys.OrderBy(x => x.Key));
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 100).ToUniTaskAsyncEnumerable().ToDictionaryAsync(x => x, x => x * 2);
|
||||
var ys = Enumerable.Range(1, 100).ToDictionary(x => x, x => x * 2);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.OrderBy(x => x.Key).Should().Equal(ys.OrderBy(x => x.Key));
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 0).ToUniTaskAsyncEnumerable().ToDictionaryAsync(x => x, x => x * 2);
|
||||
var ys = Enumerable.Range(1, 0).ToDictionary(x => x, x => x * 2);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.OrderBy(x => x.Key).Should().Equal(ys.OrderBy(x => x.Key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,34 +126,34 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.ToLookup(x => x);
|
||||
|
||||
xs.Count.Should().Be(ys.Count);
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
foreach (var key in xs.Select(x => x.Key))
|
||||
{
|
||||
xs[key].Should().BeEquivalentTo(ys[key]);
|
||||
xs[key].Should().Equal(ys[key]);
|
||||
}
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 0).ToUniTaskAsyncEnumerable().ToLookupAsync(x => x);
|
||||
var ys = Enumerable.Range(1, 0).ToLookup(x => x);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
{
|
||||
var xs = await arr.ToUniTaskAsyncEnumerable().ToLookupAsync(x => x, x => x * 2);
|
||||
var ys = arr.ToLookup(x => x, x => x * 2);
|
||||
|
||||
xs.Count.Should().Be(ys.Count);
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
foreach (var key in xs.Select(x => x.Key))
|
||||
{
|
||||
xs[key].Should().BeEquivalentTo(ys[key]);
|
||||
xs[key].Should().Equal(ys[key]);
|
||||
}
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Range(1, 0).ToUniTaskAsyncEnumerable().ToLookupAsync(x => x, x => x * 2);
|
||||
var ys = Enumerable.Range(1, 0).ToLookup(x => x, x => x * 2);
|
||||
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,13 +164,13 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Enumerable.Range(1, 100).ToUniTaskAsyncEnumerable().ToListAsync();
|
||||
var ys = Enumerable.Range(1, 100).ToList();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Empty<int>().ToUniTaskAsyncEnumerable().ToListAsync();
|
||||
var ys = Enumerable.Empty<int>().ToList();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,13 +181,13 @@ namespace NetCoreTests.Linq
|
||||
var xs = await new[] { 1, 20, 4, 5, 20, 4, 6 }.ToUniTaskAsyncEnumerable().ToHashSetAsync();
|
||||
var ys = new[] { 1, 20, 4, 5, 20, 4, 6 }.ToHashSet();
|
||||
|
||||
xs.OrderBy(x => x).Should().BeEquivalentTo(ys.OrderBy(x => x));
|
||||
xs.OrderBy(x => x).Should().Equal(ys.OrderBy(x => x));
|
||||
}
|
||||
{
|
||||
var xs = await Enumerable.Empty<int>().ToUniTaskAsyncEnumerable().ToHashSetAsync();
|
||||
var ys = Enumerable.Empty<int>().ToHashSet();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
170
src/UniTask.NetCoreTests/Linq/CreateTest.cs
Normal file
170
src/UniTask.NetCoreTests/Linq/CreateTest.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
#pragma warning disable CS1998
|
||||
#pragma warning disable CS0162
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests.Linq
|
||||
{
|
||||
public class CreateTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task SyncCreation()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = await UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
await writer.YieldAsync(from + i);
|
||||
}
|
||||
}).ToArrayAsync();
|
||||
|
||||
var ys = await Range(from, count).AsUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncManually()
|
||||
{
|
||||
var list = new List<int>();
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
list.Add(100);
|
||||
await writer.YieldAsync(10);
|
||||
|
||||
list.Add(200);
|
||||
await writer.YieldAsync(20);
|
||||
|
||||
list.Add(300);
|
||||
await writer.YieldAsync(30);
|
||||
|
||||
list.Add(400);
|
||||
});
|
||||
|
||||
list.Should().BeEmpty();
|
||||
var e = xs.GetAsyncEnumerator();
|
||||
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().Equal(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncExceptionFirst()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
throw new UniTaskTestException();
|
||||
await writer.YieldAsync(from + i);
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncException()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
await writer.YieldAsync(from + i);
|
||||
|
||||
if (i == 15)
|
||||
{
|
||||
throw new UniTaskTestException();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ASyncManually()
|
||||
{
|
||||
var list = new List<int>();
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(100);
|
||||
await writer.YieldAsync(10);
|
||||
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(200);
|
||||
await writer.YieldAsync(20);
|
||||
|
||||
await UniTask.Yield();
|
||||
list.Add(300);
|
||||
await UniTask.Yield();
|
||||
await writer.YieldAsync(30);
|
||||
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(400);
|
||||
});
|
||||
|
||||
list.Should().BeEmpty();
|
||||
var e = xs.GetAsyncEnumerator();
|
||||
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().Equal(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().Equal(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
async IAsyncEnumerable<int> Range(int from, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return from + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(start, count).ToArrayAsync();
|
||||
var ys = Enumerable.Range(start, count).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -36,7 +36,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Repeat(value, count).ToArrayAsync();
|
||||
var ys = Enumerable.Repeat(value, count).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -45,7 +45,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Empty<int>().ToArrayAsync();
|
||||
var ys = Enumerable.Empty<int>().ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
||||
@@ -23,26 +23,26 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var a = await src.Where(x => x % 2 == 0).ToArrayAsync();
|
||||
var expected = range.Where(x => x % 2 == 0).ToArray();
|
||||
a.Should().BeEquivalentTo(expected);
|
||||
a.Should().Equal(expected);
|
||||
}
|
||||
{
|
||||
var a = await src.Where((x, i) => (x + i) % 2 == 0).ToArrayAsync();
|
||||
var expected = range.Where((x, i) => (x + i) % 2 == 0).ToArray();
|
||||
a.Should().BeEquivalentTo(expected);
|
||||
a.Should().Equal(expected);
|
||||
}
|
||||
{
|
||||
var a = await src.WhereAwait(x => UniTask.Run(() => x % 2 == 0)).ToArrayAsync();
|
||||
var b = await src.WhereAwait(x => UniTask.FromResult(x % 2 == 0)).ToArrayAsync();
|
||||
var expected = range.Where(x => x % 2 == 0).ToArray();
|
||||
a.Should().BeEquivalentTo(expected);
|
||||
b.Should().BeEquivalentTo(expected);
|
||||
a.Should().Equal(expected);
|
||||
b.Should().Equal(expected);
|
||||
}
|
||||
{
|
||||
var a = await src.WhereAwait((x, i) => UniTask.Run(() => (x + i) % 2 == 0)).ToArrayAsync();
|
||||
var b = await src.WhereAwait((x, i) => UniTask.FromResult((x + i) % 2 == 0)).ToArrayAsync();
|
||||
var expected = range.Where((x, i) => (x + i) % 2 == 0).ToArray();
|
||||
a.Should().BeEquivalentTo(expected);
|
||||
b.Should().BeEquivalentTo(expected);
|
||||
a.Should().Equal(expected);
|
||||
b.Should().Equal(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace NetCoreTests.Linq
|
||||
var a = await data.ToUniTaskAsyncEnumerable().OfType<int>().ToArrayAsync();
|
||||
var b = data.OfType<int>().ToArray();
|
||||
|
||||
a.Should().BeEquivalentTo(b);
|
||||
a.Should().Equal(b);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace NetCoreTests.Linq
|
||||
var a = await data.ToUniTaskAsyncEnumerable().Cast<int>().ToArrayAsync();
|
||||
var b = data.Cast<int>().ToArray();
|
||||
|
||||
a.Should().BeEquivalentTo(b);
|
||||
a.Should().Equal(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await outer.ToUniTaskAsyncEnumerable().Join(inner.ToUniTaskAsyncEnumerable(), x => x, x => x, (x, y) => (x, y)).ToArrayAsync();
|
||||
var ys = outer.Join(inner, x => x, x => x, (x, y) => (x, y)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await outer.ToUniTaskAsyncEnumerable().JoinAwait(inner.ToUniTaskAsyncEnumerable(), x => RandomRun(x), x => RandomRun(x), (x, y) => RandomRun((x, y))).ToArrayAsync();
|
||||
var ys = outer.Join(inner, x => x, x => x, (x, y) => (x, y)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await outer.ToUniTaskAsyncEnumerable().JoinAwaitWithCancellation(inner.ToUniTaskAsyncEnumerable(), (x, _) => RandomRun(x), (x, _) => RandomRun(x), (x, y, _) => RandomRun((x, y))).ToArrayAsync();
|
||||
var ys = outer.Join(inner, x => x, x => x, (x, y) => (x, y)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x, (key, xs) => (key, xs.ToArray())).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().BeEquivalentTo(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().Equal(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -139,7 +139,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -147,7 +147,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x, (key, xs) => (key, xs.ToArray())).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().BeEquivalentTo(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().Equal(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -155,7 +155,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.Key).Should().BeEquivalentTo(ys.OrderBy(x => x.Key));
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -163,7 +163,7 @@ namespace NetCoreTests.Linq
|
||||
var ys = arr.GroupBy(x => x, (key, xs) => (key, xs.ToArray())).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().BeEquivalentTo(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
xs.OrderBy(x => x.key).SelectMany(x => x.Item2).Should().Equal(ys.OrderBy(x => x.key).SelectMany(x => x.Item2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,21 +199,21 @@ namespace NetCoreTests.Linq
|
||||
var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await outer.ToUniTaskAsyncEnumerable().GroupJoinAwait(inner.ToUniTaskAsyncEnumerable(), x => RandomRun(x), x => RandomRun(x), (x, y) => RandomRun((x, string.Join(", ", y)))).ToArrayAsync();
|
||||
var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await outer.ToUniTaskAsyncEnumerable().GroupJoinAwaitWithCancellation(inner.ToUniTaskAsyncEnumerable(), (x, _) => RandomRun(x), (x, _) => RandomRun(x), (x, y, _) => RandomRun((x, string.Join(", ", y)))).ToArrayAsync();
|
||||
var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray();
|
||||
|
||||
xs.Length.Should().Be(ys.Length);
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).Skip(skipCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).Skip(skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -52,7 +52,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipLast(skipCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipLast(skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -77,7 +77,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeLast(takeCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeLast(takeCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -103,7 +103,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).Take(takeCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).Take(takeCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -130,37 +130,37 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhile(x => x < skipCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhile((x, i) => x < (skipCount - i)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhileAwait(x => UniTask.Run(() => x < skipCount)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhileAwait((x, i) => UniTask.Run(() => x < (skipCount - i))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhileAwaitWithCancellation((x, _) => UniTask.Run(() => x < skipCount)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).SkipWhileAwaitWithCancellation((x, i, _) => UniTask.Run(() => x < (skipCount - i))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).SkipWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,37 +213,37 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhile(x => x < skipCount).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhile((x, i) => x < (skipCount - i)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhileAwait(x => UniTask.Run(() => x < skipCount)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhileAwait((x, i) => UniTask.Run(() => x < (skipCount - i))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhileAwaitWithCancellation((x, _) => UniTask.Run(() => x < skipCount)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile(x => x < skipCount).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, collection).TakeWhileAwaitWithCancellation((x, i, _) => UniTask.Run(() => x < (skipCount - i))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, collection).TakeWhile((x, i) => x < (skipCount - i)).ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await Enumerable.Range(start, count).ToUniTaskAsyncEnumerable().Reverse().ToArrayAsync();
|
||||
var ys = Enumerable.Range(start, count).Reverse().ToArray();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -46,18 +46,18 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, count).Select(x => x * x).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, count).Select(x => x * x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
|
||||
var zs = await UniTaskAsyncEnumerable.Range(1, count).SelectAwait((x) => UniTask.Run(() => x * x)).ToArrayAsync();
|
||||
zs.Should().BeEquivalentTo(ys);
|
||||
zs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, count).Select((x, i) => x * x * i).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, count).Select((x, i) => x * x * i).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
|
||||
var zs = await UniTaskAsyncEnumerable.Range(1, count).SelectAwait((x, i) => UniTask.Run(() => x * x * i)).ToArrayAsync();
|
||||
zs.Should().BeEquivalentTo(ys);
|
||||
zs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,22 +98,22 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount * x)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount * x), (x, y) => x * y).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
// await
|
||||
@@ -121,22 +121,22 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
// with cancel
|
||||
@@ -144,22 +144,22 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,17 +219,17 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).Zip(UniTaskAsyncEnumerable.Range(99, rightCount)).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).ZipAwait(UniTaskAsyncEnumerable.Range(99, rightCount), (x, y) => UniTask.Run(() => (x, y))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).ZipAwaitWithCancellation(UniTaskAsyncEnumerable.Range(99, rightCount), (x, y, _) => UniTask.Run(() => (x, y))).ToArrayAsync();
|
||||
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
@@ -288,7 +288,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(0, rangeCount).Buffer(bufferCount).Select(x => string.Join(",", x)).ToArrayAsync();
|
||||
var ys = await AsyncEnumerable.Range(0, rangeCount).Buffer(bufferCount).Select(x => string.Join(",", x)).ToArrayAsync();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -305,7 +305,7 @@ namespace NetCoreTests.Linq
|
||||
var xs = await UniTaskAsyncEnumerable.Range(0, rangeCount).Buffer(bufferCount, skipCount).Select(x => string.Join(",", x)).ToArrayAsync();
|
||||
var ys = await AsyncEnumerable.Range(0, rangeCount).Buffer(bufferCount, skipCount).Select(x => string.Join(",", x)).ToArrayAsync();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -402,7 +402,7 @@ namespace NetCoreTests.Linq
|
||||
public async Task PariwiseImmediate()
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.Range(1, 5).Pairwise().ToArrayAsync();
|
||||
xs.Should().BeEquivalentTo((1, 2), (2, 3), (3, 4), (4, 5));
|
||||
xs.Should().Equal((1, 2), (2, 3), (3, 4), (4, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -426,7 +426,7 @@ namespace NetCoreTests.Linq
|
||||
|
||||
await complete;
|
||||
|
||||
list.Should().BeEquivalentTo((10, 20), (20, 30), (30, 40), (40, 50));
|
||||
list.Should().Equal((10, 20), (20, 30), (30, 40), (40, 50));
|
||||
}
|
||||
|
||||
class MyException : Exception
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace NetCoreTests.Linq
|
||||
|
||||
rp.Value = 2;
|
||||
|
||||
(await b).Should().BeEquivalentTo(1, 2);
|
||||
(await b).Should().Equal(1, 2);
|
||||
|
||||
var c = multicast.ToArrayAsync();
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace NetCoreTests.Linq
|
||||
|
||||
rp.Dispose();
|
||||
|
||||
(await a).Should().BeEquivalentTo(1, 2, 3, 4, 5);
|
||||
(await c).Should().BeEquivalentTo(3, 4, 5);
|
||||
(await a).Should().Equal(1, 2, 3, 4, 5);
|
||||
(await c).Should().Equal(3, 4, 5);
|
||||
|
||||
disp.Dispose();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace NetCoreTests.Linq
|
||||
|
||||
rp.Value = 2;
|
||||
|
||||
(await b).Should().BeEquivalentTo(1, 2);
|
||||
(await b).Should().Equal(1, 2);
|
||||
|
||||
var c = multicast.ToArrayAsync();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace NetCoreTests.Linq
|
||||
l.Add(x);
|
||||
});
|
||||
|
||||
l.Should().BeEquivalentTo(100, 110, 120, 130, 140, 150, 160, 170, 180, 190);
|
||||
l.Should().Equal(100, 110, 120, 130, 140, 150, 160, 170, 180, 190);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var ys = array.Distinct().ToArray();
|
||||
{
|
||||
(await array.ToUniTaskAsyncEnumerable().Distinct().ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().Distinct(x => x).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctAwait(x => UniTask.Run(() => x)).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctAwaitWithCancellation((x, _) => UniTask.Run(() => x)).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().Distinct().ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().Distinct(x => x).ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctAwait(x => UniTask.Run(() => x)).ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctAwaitWithCancellation((x, _) => UniTask.Run(() => x)).ToArrayAsync()).Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +71,10 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var ys = await array.ToAsyncEnumerable().DistinctUntilChanged().ToArrayAsync();
|
||||
{
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChanged().ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChanged(x => x).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChangedAwait(x => UniTask.Run(() => x)).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChangedAwaitWithCancellation((x, _) => UniTask.Run(() => x)).ToArrayAsync()).Should().BeEquivalentTo(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChanged().ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChanged(x => x).ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChangedAwait(x => UniTask.Run(() => x)).ToArrayAsync()).Should().Equal(ys);
|
||||
(await array.ToUniTaskAsyncEnumerable().DistinctUntilChangedAwaitWithCancellation((x, _) => UniTask.Run(() => x)).ToArrayAsync()).Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await a1.ToUniTaskAsyncEnumerable().Except(a2.ToUniTaskAsyncEnumerable()).ToArrayAsync();
|
||||
var ys = a1.Except(a2).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await a1.ToUniTaskAsyncEnumerable().Intersect(a2.ToUniTaskAsyncEnumerable()).ToArrayAsync();
|
||||
var ys = a1.Intersect(a2).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await a1.ToUniTaskAsyncEnumerable().Union(a2.ToUniTaskAsyncEnumerable()).ToArrayAsync();
|
||||
var ys = a1.Union(a2).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,32 +59,32 @@ namespace NetCoreTests.Linq
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderBy(x => x).ToArrayAsync();
|
||||
var ys = array.OrderBy(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderByDescending(x => x).ToArrayAsync();
|
||||
var ys = array.OrderByDescending(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderByAwait(RandomRun).ToArrayAsync();
|
||||
var ys = array.OrderBy(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwait(RandomRun).ToArrayAsync();
|
||||
var ys = array.OrderByDescending(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderByAwaitWithCancellation(RandomRun).ToArrayAsync();
|
||||
var ys = array.OrderBy(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
{
|
||||
var xs = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwaitWithCancellation(RandomRun).ToArrayAsync();
|
||||
var ys = array.OrderByDescending(x => x).ToArray();
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,14 +125,14 @@ namespace NetCoreTests.Linq
|
||||
var g2 = await array.ToUniTaskAsyncEnumerable().OrderByDescending(x => x.Age).ThenByDescending(x => x.FirstName).ThenBy(x => x.LastName).ToArrayAsync();
|
||||
var h2 = await array.ToUniTaskAsyncEnumerable().OrderByDescending(x => x.Age).ThenByDescending(x => x.FirstName).ThenByDescending(x => x.LastName).ToArrayAsync();
|
||||
|
||||
a.Should().BeEquivalentTo(a2);
|
||||
b.Should().BeEquivalentTo(b2);
|
||||
c.Should().BeEquivalentTo(c2);
|
||||
d.Should().BeEquivalentTo(d2);
|
||||
e.Should().BeEquivalentTo(e2);
|
||||
f.Should().BeEquivalentTo(f2);
|
||||
g.Should().BeEquivalentTo(g2);
|
||||
h.Should().BeEquivalentTo(h2);
|
||||
a.Should().Equal(a2);
|
||||
b.Should().Equal(b2);
|
||||
c.Should().Equal(c2);
|
||||
d.Should().Equal(d2);
|
||||
e.Should().Equal(e2);
|
||||
f.Should().Equal(f2);
|
||||
g.Should().Equal(g2);
|
||||
h.Should().Equal(h2);
|
||||
}
|
||||
{
|
||||
var a2 = await array.ToUniTaskAsyncEnumerable().OrderByAwait(x => RandomRun(x.Age)).ThenByAwait(x => RandomRun(x.FirstName)).ThenByAwait(x => RandomRun(x.LastName)).ToArrayAsync();
|
||||
@@ -144,14 +144,14 @@ namespace NetCoreTests.Linq
|
||||
var g2 = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwait(x => RandomRun(x.Age)).ThenByDescendingAwait(x => RandomRun(x.FirstName)).ThenByAwait(x => RandomRun(x.LastName)).ToArrayAsync();
|
||||
var h2 = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwait(x => RandomRun(x.Age)).ThenByDescendingAwait(x => RandomRun(x.FirstName)).ThenByDescendingAwait(x => RandomRun(x.LastName)).ToArrayAsync();
|
||||
|
||||
a.Should().BeEquivalentTo(a2);
|
||||
b.Should().BeEquivalentTo(b2);
|
||||
c.Should().BeEquivalentTo(c2);
|
||||
d.Should().BeEquivalentTo(d2);
|
||||
e.Should().BeEquivalentTo(e2);
|
||||
f.Should().BeEquivalentTo(f2);
|
||||
g.Should().BeEquivalentTo(g2);
|
||||
h.Should().BeEquivalentTo(h2);
|
||||
a.Should().Equal(a2);
|
||||
b.Should().Equal(b2);
|
||||
c.Should().Equal(c2);
|
||||
d.Should().Equal(d2);
|
||||
e.Should().Equal(e2);
|
||||
f.Should().Equal(f2);
|
||||
g.Should().Equal(g2);
|
||||
h.Should().Equal(h2);
|
||||
}
|
||||
{
|
||||
var a2 = await array.ToUniTaskAsyncEnumerable().OrderByAwaitWithCancellation((x, ct) => RandomRun(x.Age)).ThenByAwaitWithCancellation((x, ct) => RandomRun(x.FirstName)).ThenByAwaitWithCancellation((x, ct) => RandomRun(x.LastName)).ToArrayAsync();
|
||||
@@ -163,14 +163,14 @@ namespace NetCoreTests.Linq
|
||||
var g2 = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwaitWithCancellation((x, ct) => RandomRun(x.Age)).ThenByDescendingAwaitWithCancellation((x, ct) => RandomRun(x.FirstName)).ThenByAwaitWithCancellation((x, ct) => RandomRun(x.LastName)).ToArrayAsync();
|
||||
var h2 = await array.ToUniTaskAsyncEnumerable().OrderByDescendingAwaitWithCancellation((x, ct) => RandomRun(x.Age)).ThenByDescendingAwaitWithCancellation((x, ct) => RandomRun(x.FirstName)).ThenByDescendingAwaitWithCancellation((x, ct) => RandomRun(x.LastName)).ToArrayAsync();
|
||||
|
||||
a.Should().BeEquivalentTo(a2);
|
||||
b.Should().BeEquivalentTo(b2);
|
||||
c.Should().BeEquivalentTo(c2);
|
||||
d.Should().BeEquivalentTo(d2);
|
||||
e.Should().BeEquivalentTo(e2);
|
||||
f.Should().BeEquivalentTo(f2);
|
||||
g.Should().BeEquivalentTo(g2);
|
||||
h.Should().BeEquivalentTo(h2);
|
||||
a.Should().Equal(a2);
|
||||
b.Should().Equal(b2);
|
||||
c.Should().Equal(c2);
|
||||
d.Should().Equal(d2);
|
||||
e.Should().Equal(e2);
|
||||
f.Should().Equal(f2);
|
||||
g.Should().Equal(g2);
|
||||
h.Should().Equal(h2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace NetCoreTests.Linq
|
||||
rp.Value = 4;
|
||||
rp.Value = 5;
|
||||
|
||||
(await xs).Should().BeEquivalentTo(1, 2, 3, 4, 5);
|
||||
(await xs).Should().Equal(1, 2, 3, 4, 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -39,11 +39,11 @@ namespace NetCoreTests.Linq
|
||||
rp.Value = 4;
|
||||
rp.Value = 5;
|
||||
|
||||
(await xs).Should().BeEquivalentTo(1, 2, 3, 4);
|
||||
(await xs).Should().Equal(1, 2, 3, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeUntil()
|
||||
public async Task TakeUntilCanceled()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace NetCoreTests.Linq
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 1, 10, 20 });
|
||||
foo.Should().Equal(new[] { 1, 10, 20 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
@@ -72,7 +72,7 @@ namespace NetCoreTests.Linq
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SkipUntil()
|
||||
public async Task SkipUntilCanceled()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 30, 40 });
|
||||
foo.Should().Equal(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
@@ -102,5 +102,64 @@ namespace NetCoreTests.Linq
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeUntil()
|
||||
{
|
||||
var cts = new AsyncReactiveProperty<int>(0);
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(1);
|
||||
|
||||
var xs = rp.TakeUntil(cts.WaitAsync()).ToArrayAsync();
|
||||
|
||||
var c = CancelAsync();
|
||||
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().Equal(new[] { 1, 10, 20 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
rp.Value = 10;
|
||||
await Task.Yield();
|
||||
rp.Value = 20;
|
||||
await Task.Yield();
|
||||
cts.Value = 9999;
|
||||
rp.Value = 30;
|
||||
await Task.Yield();
|
||||
rp.Value = 40;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SkipUntil()
|
||||
{
|
||||
var cts = new AsyncReactiveProperty<int>(0);
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(1);
|
||||
|
||||
var xs = rp.SkipUntil(cts.WaitAsync()).ToArrayAsync();
|
||||
|
||||
var c = CancelAsync();
|
||||
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().Equal(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
rp.Value = 10;
|
||||
await Task.Yield();
|
||||
rp.Value = 20;
|
||||
await Task.Yield();
|
||||
cts.Value = 9999;
|
||||
rp.Value = 30;
|
||||
await Task.Yield();
|
||||
rp.Value = 40;
|
||||
|
||||
rp.Dispose(); // complete.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.SetCompleted();
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace NetCoreTests
|
||||
ev.SetCompleted();
|
||||
ev.SetCanceled(default);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
one.CompletedCalled.Count.Should().Be(1);
|
||||
}
|
||||
// after removed, onemore
|
||||
@@ -59,7 +59,7 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.SetCompleted();
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace NetCoreTests
|
||||
ev.SetCompleted();
|
||||
ev.SetCanceled(default);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
one.CompletedCalled.Count.Should().Be(1);
|
||||
}
|
||||
}
|
||||
@@ -102,10 +102,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
four.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.SetCompleted();
|
||||
|
||||
@@ -120,11 +120,11 @@ namespace NetCoreTests
|
||||
ev.SetCompleted();
|
||||
ev.SetCanceled(default);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
one.CompletedCalled.Count.Should().Be(1);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.CompletedCalled.Count.Should().Be(1);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.CompletedCalled.Count.Should().Be(1);
|
||||
}
|
||||
|
||||
@@ -145,10 +145,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(30);
|
||||
ev.Add(four);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
four.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.SetCompleted();
|
||||
|
||||
@@ -163,11 +163,11 @@ namespace NetCoreTests
|
||||
ev.SetCompleted();
|
||||
ev.SetCanceled(default);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
one.CompletedCalled.Count.Should().Be(1);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.CompletedCalled.Count.Should().Be(1);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.CompletedCalled.Count.Should().Be(1);
|
||||
}
|
||||
}
|
||||
@@ -190,9 +190,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.Remove(one);
|
||||
|
||||
@@ -200,9 +200,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(50);
|
||||
ev.SetResult(60);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
three.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
@@ -222,9 +222,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.Remove(two);
|
||||
|
||||
@@ -232,9 +232,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(50);
|
||||
ev.SetResult(60);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
one.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
@@ -254,9 +254,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
|
||||
ev.Remove(three);
|
||||
|
||||
@@ -264,9 +264,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(50);
|
||||
ev.SetResult(60);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
two.NextCalled.Should().Equal(10, 20, 30, 40, 50, 60);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,9 +321,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
public void Run2()
|
||||
@@ -342,9 +342,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
public void Run3()
|
||||
@@ -363,9 +363,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10);
|
||||
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10);
|
||||
two.NextCalled.Should().Equal(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,9 +390,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Count.Should().Be(0);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
public void Run2()
|
||||
@@ -412,9 +412,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
public void Run3()
|
||||
@@ -434,9 +434,9 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
two.NextCalled.Should().BeEquivalentTo(10);
|
||||
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Should().Equal(10);
|
||||
three.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,10 +464,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
one.NextCalled.Should().Equal(10, 20, 30);
|
||||
two.NextCalled.Count.Should().Be(0);
|
||||
three.NextCalled.Count.Should().Be(0);
|
||||
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
four.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
public void Run2()
|
||||
@@ -490,10 +490,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(20);
|
||||
ev.SetResult(30);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10);
|
||||
one.NextCalled.Should().Equal(10);
|
||||
two.NextCalled.Count.Should().Be(0);
|
||||
three.NextCalled.Count.Should().Be(0);
|
||||
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||
four.NextCalled.Should().Equal(10, 20, 30);
|
||||
}
|
||||
|
||||
|
||||
@@ -533,10 +533,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(30);
|
||||
ev.SetResult(40);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
|
||||
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
|
||||
three.NextCalled.Should().BeEquivalentTo(30, 40);
|
||||
four.NextCalled.Should().BeEquivalentTo(40);
|
||||
one.NextCalled.Should().Equal(10, 20, 30, 40);
|
||||
two.NextCalled.Should().Equal(20, 30, 40);
|
||||
three.NextCalled.Should().Equal(30, 40);
|
||||
four.NextCalled.Should().Equal(40);
|
||||
}
|
||||
|
||||
public void Run2()
|
||||
@@ -573,10 +573,10 @@ namespace NetCoreTests
|
||||
ev.SetResult(30);
|
||||
ev.SetResult(40);
|
||||
|
||||
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
|
||||
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
|
||||
three.NextCalled.Should().BeEquivalentTo(30, 40);
|
||||
four.NextCalled.Should().BeEquivalentTo(40);
|
||||
one.NextCalled.Should().Equal(10, 20, 30, 40);
|
||||
two.NextCalled.Should().Equal(20, 30, 40);
|
||||
three.NextCalled.Should().Equal(30, 40);
|
||||
four.NextCalled.Should().Equal(40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class WithCancellationTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Standard()
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
var v = await UniTask.Run(() => 10).AttachExternalCancellation(cts.Token);
|
||||
|
||||
v.Should().Be(10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Cancel()
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
var t = UniTask.Create(async () =>
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
return 10;
|
||||
}).AttachExternalCancellation(cts.Token);
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await t)).CancellationToken.Should().Be(cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,11 @@ public static class EditorRunnerChecker
|
||||
{
|
||||
Debug.Log("Start");
|
||||
|
||||
var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
|
||||
Debug.Log(r.downloadHandler.text.Substring(0, 100));
|
||||
//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);
|
||||
|
||||
Debug.Log("End");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
|
||||
@@ -7,113 +7,239 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public class AsyncLazy
|
||||
{
|
||||
Func<UniTask> valueFactory;
|
||||
UniTask target;
|
||||
static Action<object> continuation = SetCompletionSource;
|
||||
|
||||
Func<UniTask> taskFactory;
|
||||
UniTaskCompletionSource completionSource;
|
||||
UniTask.Awaiter awaiter;
|
||||
|
||||
object syncLock;
|
||||
bool initialized;
|
||||
|
||||
public AsyncLazy(Func<UniTask> valueFactory)
|
||||
public AsyncLazy(Func<UniTask> taskFactory)
|
||||
{
|
||||
this.valueFactory = valueFactory;
|
||||
this.target = default;
|
||||
this.taskFactory = taskFactory;
|
||||
this.completionSource = new UniTaskCompletionSource();
|
||||
this.syncLock = new object();
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
internal AsyncLazy(UniTask value)
|
||||
internal AsyncLazy(UniTask task)
|
||||
{
|
||||
this.valueFactory = null;
|
||||
this.target = value;
|
||||
this.taskFactory = null;
|
||||
this.completionSource = new UniTaskCompletionSource();
|
||||
this.syncLock = null;
|
||||
this.initialized = true;
|
||||
|
||||
var awaiter = task.GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
SetCompletionSource(awaiter);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.awaiter = awaiter;
|
||||
awaiter.SourceOnCompleted(continuation, this);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask Task => EnsureInitialized();
|
||||
public UniTask Task
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureInitialized();
|
||||
return completionSource.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
|
||||
|
||||
UniTask EnsureInitialized()
|
||||
public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
|
||||
|
||||
void EnsureInitialized()
|
||||
{
|
||||
if (Volatile.Read(ref initialized))
|
||||
{
|
||||
return target;
|
||||
return;
|
||||
}
|
||||
|
||||
return EnsureInitializedCore();
|
||||
EnsureInitializedCore();
|
||||
}
|
||||
|
||||
UniTask EnsureInitializedCore()
|
||||
void EnsureInitializedCore()
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
if (!Volatile.Read(ref initialized))
|
||||
{
|
||||
var f = Interlocked.Exchange(ref valueFactory, null);
|
||||
var f = Interlocked.Exchange(ref taskFactory, null);
|
||||
if (f != null)
|
||||
{
|
||||
target = f().Preserve(); // with preserve(allow multiple await).
|
||||
var task = f();
|
||||
var awaiter = task.GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
SetCompletionSource(awaiter);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.awaiter = awaiter;
|
||||
awaiter.SourceOnCompleted(continuation, this);
|
||||
}
|
||||
|
||||
Volatile.Write(ref initialized, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
void SetCompletionSource(in UniTask.Awaiter awaiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter.GetResult();
|
||||
completionSource.TrySetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetCompletionSource(object state)
|
||||
{
|
||||
var self = (AsyncLazy)state;
|
||||
try
|
||||
{
|
||||
self.awaiter.GetResult();
|
||||
self.completionSource.TrySetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.awaiter = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AsyncLazy<T>
|
||||
{
|
||||
Func<UniTask<T>> valueFactory;
|
||||
UniTask<T> target;
|
||||
static Action<object> continuation = SetCompletionSource;
|
||||
|
||||
Func<UniTask<T>> taskFactory;
|
||||
UniTaskCompletionSource<T> completionSource;
|
||||
UniTask<T>.Awaiter awaiter;
|
||||
|
||||
object syncLock;
|
||||
bool initialized;
|
||||
|
||||
public AsyncLazy(Func<UniTask<T>> valueFactory)
|
||||
public AsyncLazy(Func<UniTask<T>> taskFactory)
|
||||
{
|
||||
this.valueFactory = valueFactory;
|
||||
this.target = default;
|
||||
this.taskFactory = taskFactory;
|
||||
this.completionSource = new UniTaskCompletionSource<T>();
|
||||
this.syncLock = new object();
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
internal AsyncLazy(UniTask<T> value)
|
||||
internal AsyncLazy(UniTask<T> task)
|
||||
{
|
||||
this.valueFactory = null;
|
||||
this.target = value;
|
||||
this.taskFactory = null;
|
||||
this.completionSource = new UniTaskCompletionSource<T>();
|
||||
this.syncLock = null;
|
||||
this.initialized = true;
|
||||
|
||||
var awaiter = task.GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
SetCompletionSource(awaiter);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.awaiter = awaiter;
|
||||
awaiter.SourceOnCompleted(continuation, this);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask<T> Task => EnsureInitialized();
|
||||
public UniTask<T> Task
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureInitialized();
|
||||
return completionSource.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask<T>.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
|
||||
|
||||
UniTask<T> EnsureInitialized()
|
||||
public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
|
||||
|
||||
void EnsureInitialized()
|
||||
{
|
||||
if (Volatile.Read(ref initialized))
|
||||
{
|
||||
return target;
|
||||
return;
|
||||
}
|
||||
|
||||
return EnsureInitializedCore();
|
||||
EnsureInitializedCore();
|
||||
}
|
||||
|
||||
UniTask<T> EnsureInitializedCore()
|
||||
void EnsureInitializedCore()
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
if (!Volatile.Read(ref initialized))
|
||||
{
|
||||
var f = Interlocked.Exchange(ref valueFactory, null);
|
||||
var f = Interlocked.Exchange(ref taskFactory, null);
|
||||
if (f != null)
|
||||
{
|
||||
target = f().Preserve(); // with preserve(allow multiple await).
|
||||
var task = f();
|
||||
var awaiter = task.GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
SetCompletionSource(awaiter);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.awaiter = awaiter;
|
||||
awaiter.SourceOnCompleted(continuation, this);
|
||||
}
|
||||
|
||||
Volatile.Write(ref initialized, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = awaiter.GetResult();
|
||||
completionSource.TrySetResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetCompletionSource(object state)
|
||||
{
|
||||
var self = (AsyncLazy<T>)state;
|
||||
try
|
||||
{
|
||||
var result = self.awaiter.GetResult();
|
||||
self.completionSource.TrySetResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.awaiter = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,8 @@ namespace Cysharp.Threading.Tasks
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
WaitAsyncSource nextNode;
|
||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
@@ -143,14 +144,6 @@ namespace Cysharp.Threading.Tasks
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitAsyncSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WaitAsyncSource)state;
|
||||
@@ -412,7 +405,8 @@ namespace Cysharp.Threading.Tasks
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
WaitAsyncSource nextNode;
|
||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
@@ -468,14 +462,6 @@ namespace Cysharp.Threading.Tasks
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitAsyncSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WaitAsyncSource)state;
|
||||
|
||||
@@ -11,6 +11,55 @@ namespace Cysharp.Threading.Tasks
|
||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
||||
static readonly Action<object> disposeCallback = DisposeCallback;
|
||||
|
||||
public static CancellationToken ToCancellationToken(this UniTask task)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
ToCancellationTokenCore(task, cts).Forget();
|
||||
return cts.Token;
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
|
||||
{
|
||||
if (linkToken.IsCancellationRequested)
|
||||
{
|
||||
return linkToken;
|
||||
}
|
||||
|
||||
if (!linkToken.CanBeCanceled)
|
||||
{
|
||||
return ToCancellationToken(task);
|
||||
}
|
||||
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
|
||||
ToCancellationTokenCore(task, cts).Forget();
|
||||
|
||||
return cts.Token;
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
|
||||
{
|
||||
return ToCancellationToken(task.AsUniTask());
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
|
||||
{
|
||||
return ToCancellationToken(task.AsUniTask(), linkToken);
|
||||
}
|
||||
|
||||
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
cts.Cancel();
|
||||
cts.Dispose();
|
||||
}
|
||||
|
||||
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
|
||||
@@ -4,31 +4,29 @@ using System.Threading;
|
||||
using UnityEngine;
|
||||
using Cysharp.Threading.Tasks.Triggers;
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class CancellationTokenSourceExtensions
|
||||
|
||||
public static partial class CancellationTokenSourceExtensions
|
||||
{
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
readonly static Action<object> CancelCancellationTokenSourceStateDelegate = new Action<object>(CancelCancellationTokenSourceState);
|
||||
|
||||
static void CancelCancellationTokenSourceState(object state)
|
||||
{
|
||||
var delay = UniTask.Delay(millisecondsDelay, ignoreTimeScale, delayTiming, cts.Token);
|
||||
CancelAfterCore(cts, delay).Forget();
|
||||
var cts = (CancellationTokenSource)state;
|
||||
cts.Cancel();
|
||||
}
|
||||
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
var delay = UniTask.Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cts.Token);
|
||||
CancelAfterCore(cts, delay).Forget();
|
||||
return CancelAfterSlim(cts, TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming);
|
||||
}
|
||||
|
||||
static async UniTaskVoid CancelAfterCore(CancellationTokenSource cts, UniTask delayTask)
|
||||
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
var alreadyCanceled = await delayTask.SuppressCancellationThrow();
|
||||
if (!alreadyCanceled)
|
||||
{
|
||||
cts.Cancel();
|
||||
cts.Dispose();
|
||||
}
|
||||
return PlayerLoopTimer.StartNew(delayTimeSpan, false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts);
|
||||
}
|
||||
|
||||
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Component component)
|
||||
@@ -39,11 +37,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
|
||||
{
|
||||
var trigger = gameObject.GetAsyncDestroyTrigger();
|
||||
trigger.CancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var cts2 = (CancellationTokenSource)state;
|
||||
cts2.Cancel();
|
||||
}, cts);
|
||||
trigger.CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
@@ -8,6 +8,10 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
|
||||
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
|
||||
// but currently it is labeled `Won't Fix`.
|
||||
|
||||
internal interface IStateMachineRunner
|
||||
{
|
||||
Action MoveNext { get; }
|
||||
@@ -83,7 +87,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
||||
}
|
||||
|
||||
public AsyncUniTaskVoid<TStateMachine> NextNode { get; set; }
|
||||
AsyncUniTaskVoid<TStateMachine> nextNode;
|
||||
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
|
||||
|
||||
public void Return()
|
||||
{
|
||||
@@ -153,7 +158,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine> NextNode { get; set; }
|
||||
AsyncUniTask<TStateMachine> nextNode;
|
||||
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
@@ -239,14 +245,6 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
~AsyncUniTask()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
|
||||
@@ -283,7 +281,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||
AsyncUniTask<TStateMachine, T> nextNode;
|
||||
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
@@ -376,14 +375,6 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
~AsyncUniTask()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,24 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
|
||||
{
|
||||
var source = AutoResetUniTaskCompletionSource.Create();
|
||||
coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, source));
|
||||
return source.Task;
|
||||
}
|
||||
|
||||
static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
|
||||
{
|
||||
yield return coroutineRunner.StartCoroutine(inner);
|
||||
source.TrySetResult();
|
||||
}
|
||||
|
||||
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
||||
{
|
||||
static TaskPool<EnumeratorPromise> pool;
|
||||
public EnumeratorPromise NextNode { get; set; }
|
||||
EnumeratorPromise nextNode;
|
||||
public ref EnumeratorPromise NextNode => ref nextNode;
|
||||
|
||||
static EnumeratorPromise()
|
||||
{
|
||||
@@ -44,6 +58,9 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
IEnumerator innerEnumerator;
|
||||
CancellationToken cancellationToken;
|
||||
int initialFrame;
|
||||
bool loopRunning;
|
||||
bool calledGetResult;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
@@ -66,10 +83,18 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
result.loopRunning = true;
|
||||
result.calledGetResult = false;
|
||||
result.initialFrame = -1;
|
||||
|
||||
token = result.core.Version;
|
||||
|
||||
// run immediately.
|
||||
if (result.MoveNext())
|
||||
{
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -77,11 +102,15 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
calledGetResult = true;
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!loopRunning)
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +131,38 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (calledGetResult)
|
||||
{
|
||||
loopRunning = false;
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (innerEnumerator == null) // invalid status, returned but loop running?
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
loopRunning = false;
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (initialFrame == -1)
|
||||
{
|
||||
// Time can not touch in threadpool.
|
||||
if (PlayerLoopHelper.IsMainThread)
|
||||
{
|
||||
initialFrame = Time.frameCount;
|
||||
}
|
||||
}
|
||||
else if (initialFrame == Time.frameCount)
|
||||
{
|
||||
return true; // already executed in first frame, skip.
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (innerEnumerator.MoveNext())
|
||||
@@ -117,10 +172,12 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
loopRunning = false;
|
||||
core.TrySetException(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
loopRunning = false;
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
}
|
||||
@@ -131,15 +188,8 @@ namespace Cysharp.Threading.Tasks
|
||||
core.Reset();
|
||||
innerEnumerator = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~EnumeratorPromise()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
// Unwrap YieldInstructions
|
||||
@@ -153,11 +203,10 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
else if (current is CustomYieldInstruction)
|
||||
else if (current is CustomYieldInstruction cyi)
|
||||
{
|
||||
// WWW, WaitForSecondsRealtime
|
||||
var e2 = UnwrapWaitCustomYieldInstruction((CustomYieldInstruction)current);
|
||||
while (e2.MoveNext())
|
||||
while (cyi.keepWaiting)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
@@ -183,7 +232,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return null;
|
||||
goto WARN;
|
||||
}
|
||||
}
|
||||
else if (current is IEnumerator e3)
|
||||
@@ -196,17 +245,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
// WaitForEndOfFrame, WaitForFixedUpdate, others.
|
||||
yield return null;
|
||||
goto WARN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WWW and others as CustomYieldInstruction.
|
||||
static IEnumerator UnwrapWaitCustomYieldInstruction(CustomYieldInstruction yieldInstruction)
|
||||
{
|
||||
while (yieldInstruction.keepWaiting)
|
||||
{
|
||||
continue;
|
||||
|
||||
WARN:
|
||||
// WaitForEndOfFrame, WaitForFixedUpdate, others.
|
||||
UnityEngine.Debug.LogWarning($"yield {current.GetType().Name} is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead.");
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
@@ -216,12 +262,12 @@ namespace Cysharp.Threading.Tasks
|
||||
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
|
||||
{
|
||||
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
|
||||
var startTime = DateTimeOffset.UtcNow;
|
||||
var elapsed = 0.0f;
|
||||
while (true)
|
||||
{
|
||||
yield return null;
|
||||
|
||||
var elapsed = (DateTimeOffset.UtcNow - startTime).TotalSeconds;
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= second)
|
||||
{
|
||||
break;
|
||||
@@ -238,5 +284,4 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5b9231662e24c942b544bd85d4b39cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,24 +11,39 @@ using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class AddressableAsyncExtensions
|
||||
public static class AddressablesAsyncExtensions
|
||||
{
|
||||
#region AsyncOperationHandle
|
||||
#region AsyncOperationHandle
|
||||
|
||||
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||
{
|
||||
return new AsyncOperationHandleAwaiter(handle);
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle.IsDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationHandleWithCancellationSource.Create(handle, cancellationToken, out var token), token);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (handle.IsDone) return UniTask.CompletedTask;
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
// autoReleaseHandle:true handle is invalid(immediately internal handle == null) so return completed.
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
return UniTask.FromException(handle.OperationException);
|
||||
}
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
@@ -77,29 +92,31 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource>
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleWithCancellationSource> pool;
|
||||
public AsyncOperationHandleWithCancellationSource NextNode { get; set; }
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||
AsyncOperationHandleConfiguredSource nextNode;
|
||||
public ref AsyncOperationHandleConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncOperationHandleWithCancellationSource()
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle> continuationAction;
|
||||
AsyncOperationHandle handle;
|
||||
CancellationToken cancellationToken;
|
||||
IProgress<float> progress;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationHandleWithCancellationSource()
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -108,16 +125,17 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleWithCancellationSource();
|
||||
result = new AsyncOperationHandleConfiguredSource();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
|
||||
@@ -136,7 +154,11 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
@@ -182,238 +204,85 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleWithCancellationSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle handle;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region AsyncOperationHandle_T
|
||||
#region AsyncOperationHandle_T
|
||||
|
||||
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||
{
|
||||
return new AsyncOperationHandleAwaiter<T>(handle);
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||
return new UniTask<T>(AsyncOperationHandleWithCancellationSource<T>.Create(handle, cancellationToken, out var token), token);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
throw new Exception("Attempting to use an invalid operation handle");
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
return UniTask.FromException<T>(handle.OperationException);
|
||||
}
|
||||
return UniTask.FromResult(handle.Result);
|
||||
}
|
||||
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
{
|
||||
AsyncOperationHandle<T> handle;
|
||||
Action<AsyncOperationHandle> continuationAction;
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||
AsyncOperationHandleConfiguredSource<T> nextNode;
|
||||
public ref AsyncOperationHandleConfiguredSource<T> NextNode => ref nextNode;
|
||||
|
||||
public AsyncOperationHandleAwaiter(AsyncOperationHandle<T> handle)
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
this.handle = handle;
|
||||
this.continuationAction = null;
|
||||
}
|
||||
|
||||
public bool IsCompleted => handle.IsDone;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
if (continuationAction != null)
|
||||
{
|
||||
handle.CompletedTypeless -= continuationAction;
|
||||
continuationAction = null;
|
||||
}
|
||||
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
var e = handle.OperationException;
|
||||
handle = default;
|
||||
ExceptionDispatchInfo.Capture(e).Throw();
|
||||
}
|
||||
|
||||
var result = handle.Result;
|
||||
handle = default;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
UnsafeOnCompleted(continuation);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||
handle.CompletedTypeless += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleWithCancellationSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource<T>>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleWithCancellationSource<T>> pool;
|
||||
public AsyncOperationHandleWithCancellationSource<T> NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource<T>), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
||||
AsyncOperationHandle<T> handle;
|
||||
CancellationToken cancellationToken;
|
||||
IProgress<float> progress;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncOperationHandleWithCancellationSource()
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -422,16 +291,17 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleWithCancellationSource<T>();
|
||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
result.progress = progress;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
|
||||
@@ -439,7 +309,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperationHandle<T> _)
|
||||
void Continuation(AsyncOperationHandle<T> argHandle)
|
||||
{
|
||||
handle.Completed -= continuationAction;
|
||||
|
||||
@@ -450,13 +320,17 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(argHandle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(handle.Result);
|
||||
core.TrySetResult(argHandle.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,130 +375,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleWithCancellationSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle<T> handle;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(handle.Result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -637,17 +392,9 @@ namespace Cysharp.Threading.Tasks
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
27
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables/UniTask.Addressables.asmdef
vendored
Normal file
27
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables/UniTask.Addressables.asmdef
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "UniTask.Addressables",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"Unity.ResourceManager"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.addressables.cn",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 593a5b492d29ac6448b1ebf7f035ef33
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25cb2f742bfeb1d48a4e65d3140b955d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,24 +11,33 @@ using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
// The idea of TweenCancelBehaviour is borrowed from https://www.shibuya24.info/entry/dotween_async_await
|
||||
public enum TweenCancelBehaviour
|
||||
{
|
||||
Kill,
|
||||
KillWithCompleteCallback,
|
||||
Complete,
|
||||
CompleteWithSeqeunceCallback,
|
||||
CompleteWithSequenceCallback,
|
||||
CancelAwait,
|
||||
|
||||
// AndCancelAwait
|
||||
KillAndCancelAwait,
|
||||
KillWithCompleteCallbackAndCancelAwait,
|
||||
CompleteAndCancelAwait,
|
||||
CompleteWithSeqeunceCallbackAndCancelAwait
|
||||
CompleteWithSequenceCallbackAndCancelAwait
|
||||
}
|
||||
|
||||
public static class DOTweenAsyncExtensions
|
||||
{
|
||||
enum CallbackType
|
||||
{
|
||||
Kill,
|
||||
Complete,
|
||||
Pause,
|
||||
Play,
|
||||
Rewind,
|
||||
StepComplete
|
||||
}
|
||||
|
||||
public static TweenAwaiter GetAwaiter(this Tween tween)
|
||||
{
|
||||
return new TweenAwaiter(tween);
|
||||
@@ -39,7 +48,7 @@ namespace Cysharp.Threading.Tasks
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, out var token), token);
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
@@ -47,7 +56,47 @@ namespace Cysharp.Threading.Tasks
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, out var token), token);
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Kill, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Complete, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForPause(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Pause, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForPlay(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Play, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForRewind(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Rewind, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForStepComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.StepComplete, out var token), token);
|
||||
}
|
||||
|
||||
public struct TweenAwaiter : ICriticalNotifyCompletion
|
||||
@@ -86,33 +135,34 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
||||
{
|
||||
static TaskPool<TweenConfiguredSource> pool;
|
||||
public TweenConfiguredSource NextNode { get; set; }
|
||||
TweenConfiguredSource nextNode;
|
||||
public ref TweenConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static TweenConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||
|
||||
readonly TweenCallback onKillDelegate;
|
||||
readonly TweenCallback onCompleteCallbackDelegate;
|
||||
readonly TweenCallback onUpdateDelegate;
|
||||
|
||||
Tween tween;
|
||||
TweenCancelBehaviour cancelBehaviour;
|
||||
CancellationToken cancellationToken;
|
||||
CallbackType callbackType;
|
||||
bool canceled;
|
||||
|
||||
TweenCallback originalUpdateAction;
|
||||
TweenCallback originalCompleteAction;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
TweenConfiguredSource()
|
||||
{
|
||||
onKillDelegate = OnKill;
|
||||
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
|
||||
onUpdateDelegate = OnUpdate;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -128,6 +178,7 @@ namespace Cysharp.Threading.Tasks
|
||||
result.tween = tween;
|
||||
result.cancelBehaviour = cancelBehaviour;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.callbackType = callbackType;
|
||||
|
||||
result.originalUpdateAction = tween.onUpdate;
|
||||
result.canceled = false;
|
||||
@@ -138,7 +189,41 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
tween.onUpdate = result.onUpdateDelegate;
|
||||
tween.onKill = result.onKillDelegate;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -146,14 +231,26 @@ namespace Cysharp.Threading.Tasks
|
||||
return result;
|
||||
}
|
||||
|
||||
void OnKill()
|
||||
void OnCompleteCallbackDelegate()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
|
||||
{
|
||||
canceled = true;
|
||||
}
|
||||
}
|
||||
if (canceled)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
originalCompleteAction?.Invoke();
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
@@ -191,15 +288,39 @@ namespace Cysharp.Threading.Tasks
|
||||
this.canceled = true;
|
||||
this.tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallback:
|
||||
this.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
|
||||
this.canceled = true;
|
||||
this.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
this.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
||||
// restore to original callback
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = originalCompleteAction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.core.TrySetCanceled(this.cancellationToken);
|
||||
break;
|
||||
}
|
||||
@@ -229,10 +350,10 @@ namespace Cysharp.Threading.Tasks
|
||||
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
||||
tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallback:
|
||||
tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
|
||||
tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
@@ -272,20 +393,37 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
tween.onUpdate = originalUpdateAction;
|
||||
tween.onKill = null;
|
||||
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = originalCompleteAction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tween = default;
|
||||
cancellationToken = default;
|
||||
originalUpdateAction = default;
|
||||
originalCompleteAction = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~TweenConfiguredSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef
vendored
Normal file
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UniTask.DOTween",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"DOTween.Modules"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.demigiant.dotween",
|
||||
"expression": "",
|
||||
"define": "UNITASK_DOTWEEN_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef.meta
vendored
Normal file
7
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef.meta
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 029c1c1b674aaae47a6841a0b89ad80e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f89da606bde9a4e4e94ae1189a029887
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,224 @@
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79f4f2475e0b2c44e97ed1dee760627b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#
|
||||
var handlers = new (string name, string type)[] {
|
||||
("ValueChanged", "string"),
|
||||
("EndEdit", "string"),
|
||||
("EndTextSelection", "(string, int, int)"),
|
||||
("TextSelection", "(string, int, int)"),
|
||||
("Deselect", "string"),
|
||||
("Select", "string"),
|
||||
("Submit", "string"),
|
||||
};
|
||||
|
||||
Func<string, bool> shouldConvert = x => x.EndsWith("TextSelection");
|
||||
Func<string, string> eventName = x => shouldConvert(x) ? $"new TextSelectionEventConverter(inputField.on{x})" : $"inputField.on{x}";
|
||||
#>
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
<# foreach(var (name, type) in handlers) { #>
|
||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, cancellationToken);
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9bb9fc551a975d44a7180e022a2debe
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
130
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/TextMeshProAsyncExtensions.cs
vendored
Normal file
130
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/TextMeshProAsyncExtensions.cs
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
// <string> -> Text
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = await e.MoveNextAsync();
|
||||
repeat = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
if (rebindOnError && !repeat)
|
||||
{
|
||||
repeat = true;
|
||||
goto BIND_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moveNext) return;
|
||||
|
||||
text.text = e.Current;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <T> -> Text
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this AsyncReactiveProperty<T> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = await e.MoveNextAsync();
|
||||
repeat = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
if (rebindOnError && !repeat)
|
||||
{
|
||||
repeat = true;
|
||||
goto BIND_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moveNext) return;
|
||||
|
||||
text.text = e.Current.ToString();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6ba480edafb67d4e91bb10feb64fae5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/UniTask.TextMeshPro.asmdef
vendored
Normal file
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/UniTask.TextMeshPro.asmdef
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UniTask.TextMeshPro",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc47925d1a5fa2946bdd37746b2b5d48
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,10 +9,10 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
const int MaxArrayLength = 0X7FEFFFFF;
|
||||
const int InitialSize = 16;
|
||||
|
||||
|
||||
readonly PlayerLoopTiming timing;
|
||||
|
||||
SpinLock gate = new SpinLock();
|
||||
SpinLock gate = new SpinLock(false);
|
||||
bool dequing = false;
|
||||
|
||||
int actionListCount = 0;
|
||||
@@ -70,13 +70,17 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
public int Clear()
|
||||
{
|
||||
var rest = actionListCount + waitingListCount;
|
||||
|
||||
actionListCount = 0;
|
||||
actionList = new Action[InitialSize];
|
||||
|
||||
waitingListCount = 0;
|
||||
waitingList = new Action[InitialSize];
|
||||
|
||||
return rest;
|
||||
}
|
||||
|
||||
// delegate entrypoint.
|
||||
@@ -128,6 +132,14 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
case PlayerLoopTiming.LastPostLateUpdate:
|
||||
LastPostLateUpdate();
|
||||
break;
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
case PlayerLoopTiming.TimeUpdate:
|
||||
TimeUpdate();
|
||||
break;
|
||||
case PlayerLoopTiming.LastTimeUpdate:
|
||||
LastTimeUpdate();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -150,6 +162,10 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
void LastPreLateUpdate() => RunCore();
|
||||
void PostLateUpdate() => RunCore();
|
||||
void LastPostLateUpdate() => RunCore();
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
void TimeUpdate() => RunCore();
|
||||
void LastTimeUpdate() => RunCore();
|
||||
#endif
|
||||
|
||||
[System.Diagnostics.DebuggerHidden]
|
||||
void RunCore()
|
||||
@@ -170,10 +186,17 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
|
||||
for (int i = 0; i < actionListCount; i++)
|
||||
{
|
||||
|
||||
var action = actionList[i];
|
||||
actionList[i] = null;
|
||||
|
||||
action();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
|
||||
foreach (var candidateMethod in methods)
|
||||
{
|
||||
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>();
|
||||
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(false);
|
||||
if (attributes == null)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -48,14 +48,24 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
public int Clear()
|
||||
{
|
||||
lock (arrayLock)
|
||||
{
|
||||
var rest = 0;
|
||||
|
||||
for (var index = 0; index < loopItems.Length; index++)
|
||||
{
|
||||
if (loopItems[index] != null)
|
||||
{
|
||||
rest++;
|
||||
}
|
||||
|
||||
loopItems[index] = null;
|
||||
}
|
||||
|
||||
tail = 0;
|
||||
return rest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +118,14 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
case PlayerLoopTiming.LastPostLateUpdate:
|
||||
LastPostLateUpdate();
|
||||
break;
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
case PlayerLoopTiming.TimeUpdate:
|
||||
TimeUpdate();
|
||||
break;
|
||||
case PlayerLoopTiming.LastTimeUpdate:
|
||||
LastTimeUpdate();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -130,6 +148,10 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
void LastPreLateUpdate() => RunCore();
|
||||
void PostLateUpdate() => RunCore();
|
||||
void LastPostLateUpdate() => RunCore();
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
void TimeUpdate() => RunCore();
|
||||
void LastTimeUpdate() => RunCore();
|
||||
#endif
|
||||
|
||||
[System.Diagnostics.DebuggerHidden]
|
||||
void RunCore()
|
||||
@@ -143,7 +165,6 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
var j = tail - 1;
|
||||
|
||||
// eliminate array-bound check for i
|
||||
for (int i = 0; i < loopItems.Length; i++)
|
||||
{
|
||||
var action = loopItems[i];
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
static TaskPool<PooledDelegate<T>> pool;
|
||||
|
||||
public PooledDelegate<T> NextNode { get; set; }
|
||||
PooledDelegate<T> nextNode;
|
||||
public ref PooledDelegate<T> NextNode => ref nextNode;
|
||||
|
||||
static PooledDelegate()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
|
||||
internal static class UnityWebRequestResultExtensions
|
||||
{
|
||||
public static bool IsError(this UnityWebRequest unityWebRequest)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
var result = unityWebRequest.result;
|
||||
return (result == UnityWebRequest.Result.ConnectionError)
|
||||
|| (result == UnityWebRequest.Result.DataProcessingError)
|
||||
|| (result == UnityWebRequest.Result.ProtocolError);
|
||||
#else
|
||||
return unityWebRequest.isHttpError || unityWebRequest.isNetworkError;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 111ba0e639de1d7428af6c823ead4918
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
internal readonly struct ValueStopwatch
|
||||
{
|
||||
static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
|
||||
|
||||
readonly long startTimestamp;
|
||||
|
||||
public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());
|
||||
|
||||
ValueStopwatch(long startTimestamp)
|
||||
{
|
||||
this.startTimestamp = startTimestamp;
|
||||
}
|
||||
|
||||
public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks);
|
||||
|
||||
public bool IsInvalid => startTimestamp == 0;
|
||||
|
||||
public long ElapsedTicks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (startTimestamp == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew().");
|
||||
}
|
||||
|
||||
var delta = Stopwatch.GetTimestamp() - startTimestamp;
|
||||
return (long)(delta * TimestampToTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f16fb466974ad034c8732c79c7fd67ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -17,7 +17,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new AppendPrepend<TSource>(source, element, true);
|
||||
return new AppendPrepend<TSource>(source, element, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
if (state == State.RequireAppend)
|
||||
if (state == State.RequirePrepend)
|
||||
{
|
||||
Current = element;
|
||||
state = State.None;
|
||||
|
||||
174
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Create.cs
Normal file
174
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Create.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> Create<T>(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
|
||||
{
|
||||
Error.ThrowArgumentNullException(create, nameof(create));
|
||||
return new Create<T>(create);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAsyncWriter<T>
|
||||
{
|
||||
UniTask YieldAsync(T value);
|
||||
}
|
||||
|
||||
internal sealed class Create<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
|
||||
|
||||
public Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
|
||||
{
|
||||
this.create = create;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _Create(create, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class _Create : MoveNextSource, IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
int state = -1;
|
||||
AsyncWriter writer;
|
||||
|
||||
public _Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create, CancellationToken cancellationToken)
|
||||
{
|
||||
this.create = create;
|
||||
this.cancellationToken = cancellationToken;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public T Current { get; private set; }
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return default;
|
||||
}
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (state == -2) return default;
|
||||
|
||||
completionSource.Reset();
|
||||
MoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void MoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case -1: // init
|
||||
{
|
||||
writer = new AsyncWriter(this);
|
||||
RunWriterTask(create(writer, cancellationToken)).Forget();
|
||||
if (Volatile.Read(ref state) == -2)
|
||||
{
|
||||
return; // complete synchronously
|
||||
}
|
||||
state = 0; // wait YieldAsync, it set TrySetResult(true)
|
||||
return;
|
||||
}
|
||||
case 0:
|
||||
writer.SignalWriter();
|
||||
return;
|
||||
default:
|
||||
goto DONE;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
state = -2;
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
DONE:
|
||||
state = -2;
|
||||
completionSource.TrySetResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
async UniTaskVoid RunWriterTask(UniTask task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
goto DONE;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Volatile.Write(ref state, -2);
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
DONE:
|
||||
Volatile.Write(ref state, -2);
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
|
||||
public void SetResult(T value)
|
||||
{
|
||||
Current = value;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
|
||||
{
|
||||
readonly _Create enumerator;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
public AsyncWriter(_Create enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTask YieldAsync(T value)
|
||||
{
|
||||
core.Reset();
|
||||
enumerator.SetResult(value);
|
||||
return new UniTask(this, core.Version);
|
||||
}
|
||||
|
||||
public void SignalWriter()
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0202f723469f93945afa063bfb440d15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -88,6 +88,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -156,6 +157,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -195,6 +197,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -263,6 +266,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -302,6 +306,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -382,6 +387,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -422,6 +428,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -502,6 +509,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -541,6 +549,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -621,6 +630,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -661,6 +671,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -741,6 +752,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
187
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/SkipUntil.cs
Normal file
187
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/SkipUntil.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new SkipUntil<TSource>(source, other, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(other));
|
||||
|
||||
return new SkipUntil<TSource>(source, default, other);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly UniTask other;
|
||||
readonly Func<CancellationToken, UniTask> other2;
|
||||
|
||||
public SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
|
||||
{
|
||||
this.source = source;
|
||||
this.other = other;
|
||||
this.other2 = other2;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (other2 != null)
|
||||
{
|
||||
return new _SkipUntil(source, this.other2(cancellationToken), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new _SkipUntil(source, this.other, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _SkipUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
|
||||
bool completed;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
Exception exception;
|
||||
|
||||
public _SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
RunOther(other).Forget();
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
return UniTask.FromException<bool>(exception);
|
||||
}
|
||||
|
||||
if (cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled<bool>(cancellationToken1);
|
||||
}
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken1);
|
||||
}
|
||||
completionSource.Reset();
|
||||
|
||||
if (completed)
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (_SkipUntil)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
if (self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunOther(UniTask other)
|
||||
{
|
||||
try
|
||||
{
|
||||
await other;
|
||||
completed = true;
|
||||
SourceMoveNext();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_SkipUntil)state;
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de932d79c8d9f3841a066d05ff29edc9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -32,13 +32,17 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
sealed class _SkipUntilCanceled : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> CancelDelegate2 = OnCanceled2;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
CancellationToken cancellationToken2;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
CancellationTokenRegistration cancellationTokenRegistration2;
|
||||
|
||||
bool isCanceled;
|
||||
int isCanceled;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
@@ -48,6 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
this.cancellationToken2 = cancellationToken2;
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
if (cancellationToken1 != cancellationToken2 && cancellationToken2.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(CancelDelegate2, this);
|
||||
}
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
@@ -55,15 +67,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (cancellationToken1.IsCancellationRequested) isCanceled = true;
|
||||
if (cancellationToken2.IsCancellationRequested) isCanceled = true;
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
if (cancellationToken1.IsCancellationRequested) isCanceled = 1;
|
||||
if (cancellationToken2.IsCancellationRequested) isCanceled = 1;
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token.
|
||||
}
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
|
||||
if (isCanceled != 0)
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -102,25 +117,11 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
AGAIN:
|
||||
|
||||
if (self.isCanceled)
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
if (self.continueNext)
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.cancellationToken1.IsCancellationRequested) self.isCanceled = true;
|
||||
if (self.cancellationToken2.IsCancellationRequested) self.isCanceled = true;
|
||||
|
||||
if (self.isCanceled) goto AGAIN;
|
||||
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -130,9 +131,37 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_SkipUntilCanceled)state;
|
||||
if (self.isCanceled == 0)
|
||||
{
|
||||
if (Interlocked.Increment(ref self.isCanceled) == 1)
|
||||
{
|
||||
self.cancellationTokenRegistration2.Dispose();
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled2(object state)
|
||||
{
|
||||
var self = (_SkipUntilCanceled)state;
|
||||
if (self.isCanceled == 0)
|
||||
{
|
||||
if (Interlocked.Increment(ref self.isCanceled) == 1)
|
||||
{
|
||||
self.cancellationTokenRegistration2.Dispose();
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
cancellationTokenRegistration2.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
|
||||
@@ -29,6 +29,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
@@ -45,6 +55,50 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnError
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||
@@ -87,6 +141,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnCompleted
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||
@@ -129,6 +223,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// IObserver
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
||||
@@ -177,7 +311,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current);
|
||||
try
|
||||
{
|
||||
onNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
@@ -209,7 +350,53 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current).Forget();
|
||||
try
|
||||
{
|
||||
onNext(e.Current).Forget();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError == NopError)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
onError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
onNext(e.Current, cancellationToken).Forget();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
@@ -241,7 +428,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
try
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
observer.OnCompleted();
|
||||
}
|
||||
@@ -259,5 +453,84 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await onNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError == NopError)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
onError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await onNext(e.Current, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError == NopError)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
onError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 263479eb04c189741931fc0e2f615c2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
190
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/TakeUntil.cs
Normal file
190
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/TakeUntil.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new TakeUntil<TSource>(source, other, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(other));
|
||||
|
||||
return new TakeUntil<TSource>(source, default, other);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly UniTask other;
|
||||
readonly Func<CancellationToken, UniTask> other2;
|
||||
|
||||
public TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
|
||||
{
|
||||
this.source = source;
|
||||
this.other = other;
|
||||
this.other2 = other2;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (other2 != null)
|
||||
{
|
||||
return new _TakeUntil(source, this.other2(cancellationToken), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new _TakeUntil(source, this.other, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _TakeUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
|
||||
bool completed;
|
||||
Exception exception;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public _TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
|
||||
RunOther(other).Forget();
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
return UniTask.FromException<bool>(exception);
|
||||
}
|
||||
|
||||
if (cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled<bool>(cancellationToken1);
|
||||
}
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken1);
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (_TakeUntil)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (self.exception != null)
|
||||
{
|
||||
self.completionSource.TrySetException(self.exception);
|
||||
}
|
||||
else if (self.cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunOther(UniTask other)
|
||||
{
|
||||
try
|
||||
{
|
||||
await other;
|
||||
completed = true;
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_TakeUntil)state;
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12bda324162f15349afefc2c152ac07f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -19,8 +19,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
// UnityEngine.Debug.Log("Called ToArray");
|
||||
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
|
||||
@@ -208,7 +208,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
UnityEngine.Debug.Log("TRY_RESULT:" + target.TryGetTarget(out var _));
|
||||
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
if (this.period <= 0) this.period = 1;
|
||||
}
|
||||
|
||||
this.initialFrame = Time.frameCount;
|
||||
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
this.dueTimePhase = true;
|
||||
this.updateTiming = updateTiming;
|
||||
this.ignoreTimeScale = ignoreTimeScale;
|
||||
@@ -220,7 +220,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
if (periodFrameCount <= 0) periodFrameCount = 1;
|
||||
}
|
||||
|
||||
this.initialFrame = Time.frameCount;
|
||||
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
this.dueTimePhase = true;
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -165,6 +166,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -204,6 +206,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -281,6 +284,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -320,6 +324,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -410,6 +415,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -450,6 +456,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -540,6 +547,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -579,6 +587,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -669,6 +678,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -709,6 +719,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -799,6 +810,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ using System.Threading;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using UnityEngine.LowLevel;
|
||||
using PlayerLoopType = UnityEngine.PlayerLoop;
|
||||
#else
|
||||
using UnityEngine.Experimental.LowLevel;
|
||||
using PlayerLoopType = UnityEngine.Experimental.PlayerLoop;
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
@@ -57,6 +59,13 @@ namespace Cysharp.Threading.Tasks
|
||||
public struct UniTaskLoopRunnerLastYieldUpdate { };
|
||||
public struct UniTaskLoopRunnerLastYieldPreLateUpdate { };
|
||||
public struct UniTaskLoopRunnerLastYieldPostLateUpdate { };
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
public struct UniTaskLoopRunnerTimeUpdate { };
|
||||
public struct UniTaskLoopRunnerLastTimeUpdate { };
|
||||
public struct UniTaskLoopRunnerYieldTimeUpdate { };
|
||||
public struct UniTaskLoopRunnerLastYieldTimeUpdate { };
|
||||
#endif
|
||||
}
|
||||
|
||||
public enum PlayerLoopTiming
|
||||
@@ -80,7 +89,86 @@ namespace Cysharp.Threading.Tasks
|
||||
LastPreLateUpdate = 11,
|
||||
|
||||
PostLateUpdate = 12,
|
||||
LastPostLateUpdate = 13
|
||||
LastPostLateUpdate = 13,
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
// Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
|
||||
TimeUpdate = 14,
|
||||
LastTimeUpdate = 15,
|
||||
#endif
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum InjectPlayerLoopTimings
|
||||
{
|
||||
/// <summary>
|
||||
/// Preset: All loops(default).
|
||||
/// </summary>
|
||||
All =
|
||||
Initialization | LastInitialization |
|
||||
EarlyUpdate | LastEarlyUpdate |
|
||||
FixedUpdate | LastFixedUpdate |
|
||||
PreUpdate | LastPreUpdate |
|
||||
Update | LastUpdate |
|
||||
PreLateUpdate | LastPreLateUpdate |
|
||||
PostLateUpdate | LastPostLateUpdate
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
| TimeUpdate | LastTimeUpdate,
|
||||
#else
|
||||
,
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Preset: All without last except LastPostLateUpdate.
|
||||
/// </summary>
|
||||
Standard =
|
||||
Initialization |
|
||||
EarlyUpdate |
|
||||
FixedUpdate |
|
||||
PreUpdate |
|
||||
Update |
|
||||
PreLateUpdate |
|
||||
PostLateUpdate | LastPostLateUpdate
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
| TimeUpdate
|
||||
#endif
|
||||
,
|
||||
|
||||
/// <summary>
|
||||
/// Preset: Minimum pattern, Update | FixedUpdate | LastPostLateUpdate
|
||||
/// </summary>
|
||||
Minimum =
|
||||
Update | FixedUpdate | LastPostLateUpdate,
|
||||
|
||||
// PlayerLoopTiming
|
||||
|
||||
Initialization = 1,
|
||||
LastInitialization = 2,
|
||||
|
||||
EarlyUpdate = 4,
|
||||
LastEarlyUpdate = 8,
|
||||
|
||||
FixedUpdate = 16,
|
||||
LastFixedUpdate = 32,
|
||||
|
||||
PreUpdate = 64,
|
||||
LastPreUpdate = 128,
|
||||
|
||||
Update = 256,
|
||||
LastUpdate = 512,
|
||||
|
||||
PreLateUpdate = 1024,
|
||||
LastPreLateUpdate = 2048,
|
||||
|
||||
PostLateUpdate = 4096,
|
||||
LastPostLateUpdate = 8192
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
,
|
||||
// Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
|
||||
TimeUpdate = 16384,
|
||||
LastTimeUpdate = 32768
|
||||
#endif
|
||||
}
|
||||
|
||||
public interface IPlayerLoopItem
|
||||
@@ -90,45 +178,45 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static class PlayerLoopHelper
|
||||
{
|
||||
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext;
|
||||
static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
|
||||
static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
|
||||
|
||||
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;
|
||||
public static int MainThreadId => mainThreadId;
|
||||
internal static string ApplicationDataPath => applicationDataPath;
|
||||
|
||||
public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;
|
||||
|
||||
static int mainThreadId;
|
||||
static string applicationDataPath;
|
||||
static SynchronizationContext unitySynchronizationContetext;
|
||||
static SynchronizationContext unitySynchronizationContext;
|
||||
static ContinuationQueue[] yielders;
|
||||
static PlayerLoopRunner[] runners;
|
||||
|
||||
internal static bool IsEditorApplicationQuitting { get; private set; }
|
||||
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
|
||||
Type loopRunnerYieldType, ContinuationQueue cq, Type lastLoopRunnerYieldType, ContinuationQueue lastCq,
|
||||
Type loopRunnerType, PlayerLoopRunner runner, Type lastLoopRunnerType, PlayerLoopRunner lastRunner)
|
||||
bool injectOnFirst,
|
||||
Type loopRunnerYieldType, ContinuationQueue cq,
|
||||
Type loopRunnerType, PlayerLoopRunner runner)
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged += (state) =>
|
||||
{
|
||||
if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
|
||||
if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.ExitingEditMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (runner != null)
|
||||
{
|
||||
runner.Clear();
|
||||
}
|
||||
if (lastRunner != null)
|
||||
{
|
||||
lastRunner.Clear();
|
||||
}
|
||||
|
||||
if (cq != null)
|
||||
{
|
||||
cq.Clear();
|
||||
}
|
||||
if (lastCq != null)
|
||||
{
|
||||
lastCq.Clear();
|
||||
IsEditorApplicationQuitting = true;
|
||||
// run rest action before clear.
|
||||
if (runner != null)
|
||||
{
|
||||
runner.Run();
|
||||
runner.Clear();
|
||||
}
|
||||
if (cq != null)
|
||||
{
|
||||
cq.Run();
|
||||
cq.Clear();
|
||||
}
|
||||
IsEditorApplicationQuitting = false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -139,45 +227,69 @@ namespace Cysharp.Threading.Tasks
|
||||
updateDelegate = cq.Run
|
||||
};
|
||||
|
||||
var lastYieldLoop = new PlayerLoopSystem
|
||||
{
|
||||
type = lastLoopRunnerYieldType,
|
||||
updateDelegate = lastCq.Run
|
||||
};
|
||||
|
||||
var runnerLoop = new PlayerLoopSystem
|
||||
{
|
||||
type = loopRunnerType,
|
||||
updateDelegate = runner.Run
|
||||
};
|
||||
|
||||
var lastRunnerLoop = new PlayerLoopSystem
|
||||
// Remove items from previous initializations.
|
||||
var source = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
|
||||
var dest = new PlayerLoopSystem[source.Length + 2];
|
||||
|
||||
Array.Copy(source, 0, dest, injectOnFirst ? 2 : 0, source.Length);
|
||||
if (injectOnFirst)
|
||||
{
|
||||
type = lastLoopRunnerType,
|
||||
updateDelegate = lastRunner.Run
|
||||
dest[0] = yieldLoop;
|
||||
dest[1] = runnerLoop;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[dest.Length - 2] = yieldLoop;
|
||||
dest[dest.Length - 1] = runnerLoop;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
|
||||
{
|
||||
return loopSystem.subSystemList
|
||||
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
|
||||
{
|
||||
var loop = new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(UniTaskSynchronizationContext),
|
||||
updateDelegate = UniTaskSynchronizationContext.Run
|
||||
};
|
||||
|
||||
// Remove items from previous initializations.
|
||||
var source = loopSystem.subSystemList
|
||||
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType && ls.type != lastLoopRunnerYieldType && ls.type != lastLoopRunnerType)
|
||||
.Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
|
||||
.ToArray();
|
||||
|
||||
var dest = new PlayerLoopSystem[source.Length + 4];
|
||||
var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
|
||||
|
||||
Array.Copy(source, 0, dest, 2, source.Length);
|
||||
dest[0] = yieldLoop;
|
||||
dest[1] = runnerLoop;
|
||||
dest[dest.Length - 2] = lastYieldLoop;
|
||||
dest[dest.Length - 1] = lastRunnerLoop;
|
||||
var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
|
||||
if (index == -1)
|
||||
{
|
||||
index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
|
||||
}
|
||||
|
||||
return dest;
|
||||
dest.Insert(index + 1, loop);
|
||||
|
||||
return dest.ToArray();
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
static void Init()
|
||||
{
|
||||
// capture default(unity) sync-context.
|
||||
unitySynchronizationContetext = SynchronizationContext.Current;
|
||||
unitySynchronizationContext = SynchronizationContext.Current;
|
||||
mainThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
try
|
||||
{
|
||||
@@ -244,52 +356,130 @@ namespace Cysharp.Threading.Tasks
|
||||
if (item != null) item.Run();
|
||||
}
|
||||
}
|
||||
|
||||
UniTaskSynchronizationContext.Run();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static void Initialize(ref PlayerLoopSystem playerLoop)
|
||||
private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
|
||||
{
|
||||
for (int i = 0; i < playerLoopList.Length; i++)
|
||||
{
|
||||
if (playerLoopList[i].type == systemType)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
|
||||
}
|
||||
|
||||
static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings,
|
||||
int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
|
||||
{
|
||||
var i = FindLoopSystemIndex(copyList, loopType);
|
||||
if ((injectTimings & targetTimings) == targetTimings)
|
||||
{
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], injectOnFirst,
|
||||
loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming),
|
||||
loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
|
||||
}
|
||||
else
|
||||
{
|
||||
copyList[i].subSystemList = RemoveRunner(copyList[i], loopRunnerYieldType, loopRunnerType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
yielders = new ContinuationQueue[16];
|
||||
runners = new PlayerLoopRunner[16];
|
||||
#else
|
||||
yielders = new ContinuationQueue[14];
|
||||
runners = new PlayerLoopRunner[14];
|
||||
#endif
|
||||
|
||||
var copyList = playerLoop.subSystemList.ToArray();
|
||||
|
||||
// Initialization
|
||||
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(PlayerLoopTiming.LastInitialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.LastInitialization));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
|
||||
InjectPlayerLoopTimings.Initialization, 0, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
|
||||
InjectPlayerLoopTimings.LastInitialization, 1, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
|
||||
|
||||
// EarlyUpdate
|
||||
copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), yielders[3] = new ContinuationQueue(PlayerLoopTiming.LastEarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[2] = new PlayerLoopRunner(PlayerLoopTiming.EarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), runners[3] = new PlayerLoopRunner(PlayerLoopTiming.LastEarlyUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
|
||||
InjectPlayerLoopTimings.EarlyUpdate, 2, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
|
||||
InjectPlayerLoopTimings.LastEarlyUpdate, 3, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
|
||||
|
||||
// FixedUpdate
|
||||
copyList[2].subSystemList = InsertRunner(copyList[2], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[4] = new ContinuationQueue(PlayerLoopTiming.FixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), yielders[5] = new ContinuationQueue(PlayerLoopTiming.LastFixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[4] = new PlayerLoopRunner(PlayerLoopTiming.FixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), runners[5] = new PlayerLoopRunner(PlayerLoopTiming.LastFixedUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
|
||||
InjectPlayerLoopTimings.FixedUpdate, 4, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
|
||||
InjectPlayerLoopTimings.LastFixedUpdate, 5, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
|
||||
|
||||
// PreUpdate
|
||||
copyList[3].subSystemList = InsertRunner(copyList[3], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[6] = new ContinuationQueue(PlayerLoopTiming.PreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), yielders[7] = new ContinuationQueue(PlayerLoopTiming.LastPreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[6] = new PlayerLoopRunner(PlayerLoopTiming.PreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), runners[7] = new PlayerLoopRunner(PlayerLoopTiming.LastPreUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
|
||||
InjectPlayerLoopTimings.PreUpdate, 6, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
|
||||
InjectPlayerLoopTimings.LastPreUpdate, 7, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
|
||||
|
||||
// Update
|
||||
copyList[4].subSystemList = InsertRunner(copyList[4], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[8] = new ContinuationQueue(PlayerLoopTiming.Update),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), yielders[9] = new ContinuationQueue(PlayerLoopTiming.LastUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[8] = new PlayerLoopRunner(PlayerLoopTiming.Update),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), runners[9] = new PlayerLoopRunner(PlayerLoopTiming.LastUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
|
||||
InjectPlayerLoopTimings.Update, 8, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
|
||||
InjectPlayerLoopTimings.LastUpdate, 9, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
|
||||
|
||||
// PreLateUpdate
|
||||
copyList[5].subSystemList = InsertRunner(copyList[5], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[10] = new ContinuationQueue(PlayerLoopTiming.PreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), yielders[11] = new ContinuationQueue(PlayerLoopTiming.LastPreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[10] = new PlayerLoopRunner(PlayerLoopTiming.PreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), runners[11] = new PlayerLoopRunner(PlayerLoopTiming.LastPreLateUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
|
||||
InjectPlayerLoopTimings.PreLateUpdate, 10, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
|
||||
InjectPlayerLoopTimings.LastPreLateUpdate, 11, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
|
||||
|
||||
// PostLateUpdate
|
||||
copyList[6].subSystemList = InsertRunner(copyList[6], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[12] = new ContinuationQueue(PlayerLoopTiming.PostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), yielders[13] = new ContinuationQueue(PlayerLoopTiming.LastPostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
|
||||
InjectPlayerLoopTimings.PostLateUpdate, 12, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
|
||||
InjectPlayerLoopTimings.LastPostLateUpdate, 13, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
// TimeUpdate
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
|
||||
InjectPlayerLoopTimings.TimeUpdate, 14, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
|
||||
InjectPlayerLoopTimings.LastTimeUpdate, 15, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
|
||||
#endif
|
||||
|
||||
// Insert UniTaskSynchronizationContext to Update loop
|
||||
var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
|
||||
copyList[i].subSystemList = InsertUniTaskSynchronizationContext(copyList[i]);
|
||||
|
||||
playerLoop.subSystemList = copyList;
|
||||
PlayerLoop.SetPlayerLoop(playerLoop);
|
||||
@@ -297,13 +487,91 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
|
||||
{
|
||||
runners[(int)timing].AddAction(action);
|
||||
var runner = runners[(int)timing];
|
||||
if (runner == null)
|
||||
{
|
||||
ThrowInvalidLoopTiming(timing);
|
||||
}
|
||||
runner.AddAction(action);
|
||||
}
|
||||
|
||||
static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
|
||||
{
|
||||
throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
|
||||
}
|
||||
|
||||
public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
|
||||
{
|
||||
yielders[(int)timing].Enqueue(continuation);
|
||||
var q = yielders[(int)timing];
|
||||
if (q == null)
|
||||
{
|
||||
ThrowInvalidLoopTiming(timing);
|
||||
}
|
||||
q.Enqueue(continuation);
|
||||
}
|
||||
|
||||
// Diagnostics helper
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
|
||||
public static void DumpCurrentPlayerLoop()
|
||||
{
|
||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine($"PlayerLoop List");
|
||||
foreach (var header in playerLoop.subSystemList)
|
||||
{
|
||||
sb.AppendFormat("------{0}------", header.type.Name);
|
||||
sb.AppendLine();
|
||||
|
||||
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);
|
||||
sb.AppendLine();
|
||||
|
||||
if (subSystem.subSystemList != null)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnityEngine.Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public static bool IsInjectedUniTaskPlayerLoop()
|
||||
{
|
||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
foreach (var header in playerLoop.subSystemList)
|
||||
{
|
||||
if (header.subSystemList is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var subSystem in header.subSystemList)
|
||||
{
|
||||
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
262
src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopTimer.cs
Normal file
262
src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopTimer.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System.Threading;
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem
|
||||
{
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly Action<object> timerCallback;
|
||||
readonly object state;
|
||||
readonly PlayerLoopTiming playerLoopTiming;
|
||||
readonly bool periodic;
|
||||
|
||||
bool isRunning;
|
||||
bool tryStop;
|
||||
bool isDisposed;
|
||||
|
||||
protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
{
|
||||
this.periodic = periodic;
|
||||
this.playerLoopTiming = playerLoopTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.timerCallback = timerCallback;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// force use Realtime.
|
||||
if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
|
||||
{
|
||||
delayType = DelayType.Realtime;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (delayType)
|
||||
{
|
||||
case DelayType.UnscaledDeltaTime:
|
||||
return new IgnoreTimeScalePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
|
||||
case DelayType.Realtime:
|
||||
return new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
|
||||
case DelayType.DeltaTime:
|
||||
default:
|
||||
return new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
|
||||
}
|
||||
}
|
||||
|
||||
public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
{
|
||||
var timer = Create(interval, periodic, delayType, playerLoopTiming, cancellationToken, timerCallback, state);
|
||||
timer.Restart();
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart(Reset and Start) timer.
|
||||
/// </summary>
|
||||
public void Restart()
|
||||
{
|
||||
if (isDisposed) throw new ObjectDisposedException(null);
|
||||
|
||||
ResetCore(null); // init state
|
||||
if (!isRunning)
|
||||
{
|
||||
isRunning = true;
|
||||
PlayerLoopHelper.AddAction(playerLoopTiming, this);
|
||||
}
|
||||
tryStop = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart(Reset and Start) and change interval.
|
||||
/// </summary>
|
||||
public void Restart(TimeSpan interval)
|
||||
{
|
||||
if (isDisposed) throw new ObjectDisposedException(null);
|
||||
|
||||
ResetCore(interval); // init state
|
||||
if (!isRunning)
|
||||
{
|
||||
isRunning = true;
|
||||
PlayerLoopHelper.AddAction(playerLoopTiming, this);
|
||||
}
|
||||
tryStop = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop timer.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
tryStop = true;
|
||||
}
|
||||
|
||||
protected abstract void ResetCore(TimeSpan? newInterval);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
isDisposed = true;
|
||||
}
|
||||
|
||||
bool IPlayerLoopItem.MoveNext()
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
isRunning = false;
|
||||
return false;
|
||||
}
|
||||
if (tryStop)
|
||||
{
|
||||
isRunning = false;
|
||||
return false;
|
||||
}
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
isRunning = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MoveNextCore())
|
||||
{
|
||||
timerCallback(state);
|
||||
|
||||
if (periodic)
|
||||
{
|
||||
ResetCore(null);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isRunning = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract bool MoveNextCore();
|
||||
}
|
||||
|
||||
sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer
|
||||
{
|
||||
int initialFrame;
|
||||
float elapsed;
|
||||
float interval;
|
||||
|
||||
public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
|
||||
{
|
||||
ResetCore(interval);
|
||||
}
|
||||
|
||||
protected override bool MoveNextCore()
|
||||
{
|
||||
if (elapsed == 0.0f)
|
||||
{
|
||||
if (initialFrame == Time.frameCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= interval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void ResetCore(TimeSpan? interval)
|
||||
{
|
||||
this.elapsed = 0.0f;
|
||||
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
if (interval != null)
|
||||
{
|
||||
this.interval = (float)interval.Value.TotalSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class IgnoreTimeScalePlayerLoopTimer : PlayerLoopTimer
|
||||
{
|
||||
int initialFrame;
|
||||
float elapsed;
|
||||
float interval;
|
||||
|
||||
public IgnoreTimeScalePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
|
||||
{
|
||||
ResetCore(interval);
|
||||
}
|
||||
|
||||
protected override bool MoveNextCore()
|
||||
{
|
||||
if (elapsed == 0.0f)
|
||||
{
|
||||
if (initialFrame == Time.frameCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
if (elapsed >= interval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void ResetCore(TimeSpan? interval)
|
||||
{
|
||||
this.elapsed = 0.0f;
|
||||
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
if (interval != null)
|
||||
{
|
||||
this.interval = (float)interval.Value.TotalSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class RealtimePlayerLoopTimer : PlayerLoopTimer
|
||||
{
|
||||
ValueStopwatch stopwatch;
|
||||
long intervalTicks;
|
||||
|
||||
public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
|
||||
: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
|
||||
{
|
||||
ResetCore(interval);
|
||||
}
|
||||
|
||||
protected override bool MoveNextCore()
|
||||
{
|
||||
if (stopwatch.ElapsedTicks >= intervalTicks)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void ResetCore(TimeSpan? interval)
|
||||
{
|
||||
this.stopwatch = ValueStopwatch.StartNew();
|
||||
if (interval != null)
|
||||
{
|
||||
this.intervalTicks = interval.Value.Ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57095a17fdca7ee4380450910afc7f26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -7,12 +7,14 @@ using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
// internaly used but public, allow to user create custom operator with pooling.
|
||||
// internally used but public, allow to user create custom operator with pooling.
|
||||
|
||||
public static class TaskPool
|
||||
{
|
||||
internal static int MaxPoolSize;
|
||||
static ConcurrentDictionary<Type, Func<int>> sizes = new ConcurrentDictionary<Type, Func<int>>();
|
||||
|
||||
// avoid to use ConcurrentDictionary for safety of WebGL build.
|
||||
static Dictionary<Type, Func<int>> sizes = new Dictionary<Type, Func<int>>();
|
||||
|
||||
static TaskPool()
|
||||
{
|
||||
@@ -40,22 +42,27 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static IEnumerable<(Type, int)> GetCacheSizeInfo()
|
||||
{
|
||||
foreach (var item in sizes)
|
||||
lock (sizes)
|
||||
{
|
||||
yield return (item.Key, item.Value());
|
||||
foreach (var item in sizes)
|
||||
{
|
||||
yield return (item.Key, item.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterSizeGetter(Type type, Func<int> getSize)
|
||||
{
|
||||
sizes[type] = getSize;
|
||||
lock (sizes)
|
||||
{
|
||||
sizes[type] = getSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface ITaskPoolNode<T>
|
||||
{
|
||||
T NextNode { get; set; }
|
||||
ref T NextNode { get; }
|
||||
}
|
||||
|
||||
// mutable struct, don't mark readonly.
|
||||
@@ -77,8 +84,9 @@ namespace Cysharp.Threading.Tasks
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
ref var nextNode = ref v.NextNode;
|
||||
root = nextNode;
|
||||
nextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
|
||||
129
src/UniTask/Assets/Plugins/UniTask/Runtime/TimeoutController.cs
Normal file
129
src/UniTask/Assets/Plugins/UniTask/Runtime/TimeoutController.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
// CancellationTokenSource itself can not reuse but CancelAfter(Timeout.InfiniteTimeSpan) allows reuse if did not reach timeout.
|
||||
// Similar discussion:
|
||||
// https://github.com/dotnet/runtime/issues/4694
|
||||
// https://github.com/dotnet/runtime/issues/48492
|
||||
// This TimeoutController emulate similar implementation, using CancelAfterSlim; to achieve zero allocation timeout.
|
||||
|
||||
public sealed class TimeoutController : IDisposable
|
||||
{
|
||||
readonly static Action<object> CancelCancellationTokenSourceStateDelegate = new Action<object>(CancelCancellationTokenSourceState);
|
||||
|
||||
static void CancelCancellationTokenSourceState(object state)
|
||||
{
|
||||
var cts = (CancellationTokenSource)state;
|
||||
cts.Cancel();
|
||||
}
|
||||
|
||||
CancellationTokenSource timeoutSource;
|
||||
CancellationTokenSource linkedSource;
|
||||
PlayerLoopTimer timer;
|
||||
bool isDisposed;
|
||||
|
||||
readonly DelayType delayType;
|
||||
readonly PlayerLoopTiming delayTiming;
|
||||
readonly CancellationTokenSource originalLinkCancellationTokenSource;
|
||||
|
||||
public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
this.timeoutSource = new CancellationTokenSource();
|
||||
this.originalLinkCancellationTokenSource = null;
|
||||
this.linkedSource = null;
|
||||
this.delayType = delayType;
|
||||
this.delayTiming = delayTiming;
|
||||
}
|
||||
|
||||
public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
this.timeoutSource = new CancellationTokenSource();
|
||||
this.originalLinkCancellationTokenSource = linkCancellationTokenSource;
|
||||
this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token);
|
||||
this.delayType = delayType;
|
||||
this.delayTiming = delayTiming;
|
||||
}
|
||||
|
||||
public CancellationToken Timeout(int millisecondsTimeout)
|
||||
{
|
||||
return Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout));
|
||||
}
|
||||
|
||||
public CancellationToken Timeout(TimeSpan timeout)
|
||||
{
|
||||
if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return originalLinkCancellationTokenSource.Token;
|
||||
}
|
||||
|
||||
// Timeouted, create new source and timer.
|
||||
if (timeoutSource.IsCancellationRequested)
|
||||
{
|
||||
timeoutSource.Dispose();
|
||||
timeoutSource = new CancellationTokenSource();
|
||||
if (linkedSource != null)
|
||||
{
|
||||
this.linkedSource.Cancel();
|
||||
this.linkedSource.Dispose();
|
||||
this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
timer?.Dispose();
|
||||
timer = null;
|
||||
}
|
||||
|
||||
var useSource = (linkedSource != null) ? linkedSource : timeoutSource;
|
||||
var token = useSource.Token;
|
||||
if (timer == null)
|
||||
{
|
||||
// Timer complete => timeoutSource.Cancel() -> linkedSource will be canceled.
|
||||
// (linked)token is canceled => stop timer
|
||||
timer = PlayerLoopTimer.StartNew(timeout, false, delayType, delayTiming, token, CancelCancellationTokenSourceStateDelegate, timeoutSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer.Restart(timeout);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public bool IsTimeout()
|
||||
{
|
||||
return timeoutSource.IsCancellationRequested;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
timer?.Stop();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (isDisposed) return;
|
||||
|
||||
try
|
||||
{
|
||||
// stop timer.
|
||||
timer?.Dispose();
|
||||
|
||||
// cancel and dispose.
|
||||
timeoutSource.Cancel();
|
||||
timeoutSource.Dispose();
|
||||
if (linkedSource != null)
|
||||
{
|
||||
linkedSource.Cancel();
|
||||
linkedSource.Dispose();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6347ab34d2db6d744a654e8d62d96b96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -8,6 +8,16 @@ 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)
|
||||
{
|
||||
@@ -17,6 +27,13 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
using UnityEngine.EventSystems;
|
||||
#endif
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Triggers
|
||||
{
|
||||
@@ -715,6 +717,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
#endregion
|
||||
|
||||
#region CollisionEnter
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionEnterHandler
|
||||
{
|
||||
@@ -771,9 +774,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionEnterHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionEnterAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region CollisionEnter2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionEnter2DHandler
|
||||
{
|
||||
@@ -830,9 +835,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionEnter2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionEnter2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region CollisionExit
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionExitHandler
|
||||
{
|
||||
@@ -889,9 +896,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionExitHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionExitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region CollisionExit2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionExit2DHandler
|
||||
{
|
||||
@@ -948,9 +957,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionExit2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionExit2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region CollisionStay
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionStayHandler
|
||||
{
|
||||
@@ -1007,9 +1018,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionStayHandler)new AsyncTriggerHandler<Collision>(this, cancellationToken, true)).OnCollisionStayAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region CollisionStay2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnCollisionStay2DHandler
|
||||
{
|
||||
@@ -1066,9 +1079,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCollisionStay2DHandler)new AsyncTriggerHandler<Collision2D>(this, cancellationToken, true)).OnCollisionStay2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region ControllerColliderHit
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnControllerColliderHitHandler
|
||||
{
|
||||
@@ -1125,6 +1140,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnControllerColliderHitHandler)new AsyncTriggerHandler<ControllerColliderHit>(this, cancellationToken, true)).OnControllerColliderHitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Disable
|
||||
@@ -1423,6 +1439,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
#endregion
|
||||
|
||||
#region JointBreak
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnJointBreakHandler
|
||||
{
|
||||
@@ -1479,9 +1496,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnJointBreakHandler)new AsyncTriggerHandler<float>(this, cancellationToken, true)).OnJointBreakAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region JointBreak2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnJointBreak2DHandler
|
||||
{
|
||||
@@ -1538,9 +1557,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnJointBreak2DHandler)new AsyncTriggerHandler<Joint2D>(this, cancellationToken, true)).OnJointBreak2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseDown
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseDownHandler
|
||||
{
|
||||
@@ -1597,9 +1618,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseDownHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDownAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseDrag
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseDragHandler
|
||||
{
|
||||
@@ -1656,9 +1679,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseDragHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseDragAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseEnter
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseEnterHandler
|
||||
{
|
||||
@@ -1715,9 +1740,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseEnterHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseEnterAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseExit
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseExitHandler
|
||||
{
|
||||
@@ -1774,9 +1801,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseExitHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseExitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseOver
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseOverHandler
|
||||
{
|
||||
@@ -1833,9 +1862,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseOverHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseOverAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseUp
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseUpHandler
|
||||
{
|
||||
@@ -1892,9 +1923,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseUpHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region MouseUpAsButton
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
public interface IAsyncOnMouseUpAsButtonHandler
|
||||
{
|
||||
@@ -1951,6 +1984,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMouseUpAsButtonHandler)new AsyncTriggerHandler<AsyncUnit>(this, cancellationToken, true)).OnMouseUpAsButtonAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region ParticleCollision
|
||||
@@ -2131,7 +2165,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
#endregion
|
||||
|
||||
#region ParticleUpdateJobScheduled
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
#if UNITY_2019_3_OR_NEWER && (!UNITY_2019_1_OR_NEWER || UNITASK_PARTICLESYSTEM_SUPPORT)
|
||||
|
||||
public interface IAsyncOnParticleUpdateJobScheduledHandler
|
||||
{
|
||||
@@ -2782,6 +2816,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
#endregion
|
||||
|
||||
#region TriggerEnter
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerEnterHandler
|
||||
{
|
||||
@@ -2838,9 +2873,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerEnterHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerEnterAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region TriggerEnter2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerEnter2DHandler
|
||||
{
|
||||
@@ -2897,9 +2934,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerEnter2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerEnter2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region TriggerExit
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerExitHandler
|
||||
{
|
||||
@@ -2956,9 +2995,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerExitHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerExitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region TriggerExit2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerExit2DHandler
|
||||
{
|
||||
@@ -3015,9 +3056,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerExit2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerExit2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region TriggerStay
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerStayHandler
|
||||
{
|
||||
@@ -3074,9 +3117,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerStayHandler)new AsyncTriggerHandler<Collider>(this, cancellationToken, true)).OnTriggerStayAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region TriggerStay2D
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_PHYSICS2D_SUPPORT
|
||||
|
||||
public interface IAsyncOnTriggerStay2DHandler
|
||||
{
|
||||
@@ -3133,6 +3178,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnTriggerStay2DHandler)new AsyncTriggerHandler<Collider2D>(this, cancellationToken, true)).OnTriggerStay2DAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Validate
|
||||
@@ -3372,6 +3418,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
#endregion
|
||||
|
||||
#region BeginDrag
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnBeginDragHandler
|
||||
{
|
||||
@@ -3428,9 +3475,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnBeginDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnBeginDragAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Cancel
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnCancelHandler
|
||||
{
|
||||
@@ -3487,9 +3536,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnCancelHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnCancelAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Deselect
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnDeselectHandler
|
||||
{
|
||||
@@ -3546,9 +3597,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnDeselectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnDeselectAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Drag
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnDragHandler
|
||||
{
|
||||
@@ -3605,9 +3658,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDragAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Drop
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnDropHandler
|
||||
{
|
||||
@@ -3664,9 +3719,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnDropHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnDropAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region EndDrag
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnEndDragHandler
|
||||
{
|
||||
@@ -3723,9 +3780,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnEndDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnEndDragAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region InitializePotentialDrag
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnInitializePotentialDragHandler
|
||||
{
|
||||
@@ -3782,9 +3841,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnInitializePotentialDragHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnInitializePotentialDragAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Move
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnMoveHandler
|
||||
{
|
||||
@@ -3841,9 +3902,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnMoveHandler)new AsyncTriggerHandler<AxisEventData>(this, cancellationToken, true)).OnMoveAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region PointerClick
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnPointerClickHandler
|
||||
{
|
||||
@@ -3900,9 +3963,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnPointerClickHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerClickAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region PointerDown
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnPointerDownHandler
|
||||
{
|
||||
@@ -3959,9 +4024,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnPointerDownHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerDownAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region PointerEnter
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnPointerEnterHandler
|
||||
{
|
||||
@@ -4018,9 +4085,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnPointerEnterHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerEnterAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region PointerExit
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnPointerExitHandler
|
||||
{
|
||||
@@ -4077,9 +4146,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnPointerExitHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerExitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region PointerUp
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnPointerUpHandler
|
||||
{
|
||||
@@ -4136,9 +4207,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnPointerUpHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnPointerUpAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Scroll
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnScrollHandler
|
||||
{
|
||||
@@ -4195,9 +4268,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnScrollHandler)new AsyncTriggerHandler<PointerEventData>(this, cancellationToken, true)).OnScrollAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Select
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnSelectHandler
|
||||
{
|
||||
@@ -4254,9 +4329,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnSelectHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSelectAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Submit
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnSubmitHandler
|
||||
{
|
||||
@@ -4313,9 +4390,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnSubmitHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnSubmitAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region UpdateSelected
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
|
||||
public interface IAsyncOnUpdateSelectedHandler
|
||||
{
|
||||
@@ -4372,6 +4451,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((IAsyncOnUpdateSelectedHandler)new AsyncTriggerHandler<BaseEventData>(this, cancellationToken, true)).OnUpdateSelectedAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -25,13 +25,7 @@
|
||||
("Update", "Update", "AsyncUnit", null, empty),
|
||||
("FixedUpdate", "FixedUpdate", "AsyncUnit", null, empty),
|
||||
("LateUpdate", "LateUpdate", "AsyncUnit", null, empty),
|
||||
("MouseDown", "OnMouseDown", "AsyncUnit", null, empty),
|
||||
("MouseDrag", "OnMouseDrag", "AsyncUnit", null, empty),
|
||||
("MouseEnter", "OnMouseEnter", "AsyncUnit", null, empty),
|
||||
("MouseExit", "OnMouseExit", "AsyncUnit", null, empty),
|
||||
("MouseOver", "OnMouseOver", "AsyncUnit", null, empty),
|
||||
("MouseUp", "OnMouseUp", "AsyncUnit", null, empty),
|
||||
("MouseUpAsButton", "OnMouseUpAsButton", "AsyncUnit", null, empty),
|
||||
|
||||
("ParticleCollision", "OnParticleCollision", "GameObject", null, new []{ ("GameObject", "other") }),
|
||||
("RectTransformDimensionsChange", "OnRectTransformDimensionsChange", "AsyncUnit", null, empty),
|
||||
("RectTransformRemoved", "OnRectTransformRemoved", "AsyncUnit", null, empty),
|
||||
@@ -47,6 +41,15 @@
|
||||
("BecameInvisible", "OnBecameInvisible", "AsyncUnit", null, empty),
|
||||
("BecameVisible", "OnBecameVisible", "AsyncUnit", null, empty),
|
||||
|
||||
// Mouse... #if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
("MouseDown", "OnMouseDown", "AsyncUnit", null, empty),
|
||||
("MouseDrag", "OnMouseDrag", "AsyncUnit", null, empty),
|
||||
("MouseEnter", "OnMouseEnter", "AsyncUnit", null, empty),
|
||||
("MouseExit", "OnMouseExit", "AsyncUnit", null, empty),
|
||||
("MouseOver", "OnMouseOver", "AsyncUnit", null, empty),
|
||||
("MouseUp", "OnMouseUp", "AsyncUnit", null, empty),
|
||||
("MouseUpAsButton", "OnMouseUpAsButton", "AsyncUnit", null, empty),
|
||||
|
||||
// new in v2
|
||||
("ApplicationFocus", "OnApplicationFocus", "bool", null, new []{("bool", "hasFocus") }),
|
||||
("ApplicationPause", "OnApplicationPause", "bool", null, new []{("bool", "pauseStatus") }),
|
||||
@@ -103,20 +106,36 @@
|
||||
Func<(string argType, string argName)[], string> BuildMethodArgument = x => string.Join(", ", x.Select(y => y.argType + " " + y.argName));
|
||||
Func<(string argType, string argName)[], string> BuildResultParameter = x => x.Length == 0 ? "AsyncUnit.Default" : "(" + string.Join(", ", x.Select(y => y.argName)) + ")";
|
||||
|
||||
Func<string, bool> Is2019_3 = x => x == "ParticleUpdateJobScheduled";
|
||||
Func<string, bool> IsParticleSystem = x => x == "ParticleUpdateJobScheduled";
|
||||
Func<string, bool> IsMouseTrigger = x => x.StartsWith("Mouse");
|
||||
Func<string, string> RequirePhysicsModule = x => (x.StartsWith("Collision") || x.StartsWith("Collider") || x.StartsWith("ControllerCollider") || x.StartsWith("Joint") || x.StartsWith("Trigger"))
|
||||
? (x.Contains("2D") ? "UNITASK_PHYSICS2D_SUPPORT" : "UNITASK_PHYSICS_SUPPORT")
|
||||
: null;
|
||||
Func<string, bool> IsUguiSystem = x => x != null;
|
||||
#>
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
using UnityEngine.EventSystems;
|
||||
#endif
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Triggers
|
||||
{
|
||||
<# foreach(var t in triggers) { #>
|
||||
#region <#= t.triggerName #>
|
||||
<# if(Is2019_3(t.triggerName)) { #>
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
<# if(IsUguiSystem(t.handlerInterface)) { #>
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
<# } #>
|
||||
<# if(IsParticleSystem(t.triggerName)) { #>
|
||||
#if UNITY_2019_3_OR_NEWER && (!UNITY_2019_1_OR_NEWER || UNITASK_PARTICLESYSTEM_SUPPORT)
|
||||
<# } #>
|
||||
<# if(IsMouseTrigger(t.triggerName)) { #>
|
||||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
<# } #>
|
||||
<# if(RequirePhysicsModule(t.triggerName) != null) { #>
|
||||
#if !UNITY_2019_1_OR_NEWER || <#= RequirePhysicsModule(t.triggerName) #>
|
||||
<# } #>
|
||||
|
||||
public interface <#= ToInterfaceName(t.methodName) #>
|
||||
@@ -174,7 +193,13 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, true)).<#= t.methodName #>Async();
|
||||
}
|
||||
}
|
||||
<# if(Is2019_3(t.triggerName)) { #>
|
||||
<# if(IsUguiSystem(t.handlerInterface)) { #>
|
||||
#endif
|
||||
<# } #>
|
||||
<# if(RequirePhysicsModule(t.triggerName) != null) { #>
|
||||
#endif
|
||||
<# } #>
|
||||
<# if(IsParticleSystem(t.triggerName) || IsMouseTrigger(t.triggerName)) { #>
|
||||
#endif
|
||||
<# } #>
|
||||
#endregion
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user