mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 19:40:09 +00:00
Compare commits
324 Commits
2.2.4
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46c690e19a | ||
|
|
a9e27c03d4 | ||
|
|
73a63b7f67 | ||
|
|
30bec5d5c4 | ||
|
|
ec9204d381 | ||
|
|
9a6584ff0d | ||
|
|
98538ef7c7 | ||
|
|
519590ca6e | ||
|
|
dce4366f3e | ||
|
|
88026ab14a | ||
|
|
95998ff3f2 | ||
|
|
64285ae060 | ||
|
|
40e020fb02 | ||
|
|
e63dba1350 | ||
|
|
f213ff497e | ||
|
|
7568061eda | ||
|
|
459a572c1d | ||
|
|
06067cd4c8 | ||
|
|
d9983cfe27 | ||
|
|
70eb7cd3ee | ||
|
|
cc3c70af90 | ||
|
|
8042b29ff8 | ||
|
|
b0d01ca75f | ||
|
|
7a63ab7088 | ||
|
|
bdf102f145 | ||
|
|
41cea030ab | ||
|
|
f9fd769be7 | ||
|
|
579304fe47 | ||
|
|
740ca7ef01 | ||
|
|
7c0f199fe0 | ||
|
|
9a3ec31533 | ||
|
|
37d8f4f48e | ||
|
|
27a0c06ede | ||
|
|
e4082ecd75 | ||
|
|
3b0fd784ff | ||
|
|
dc9ebfd765 | ||
|
|
005c83fbd7 | ||
|
|
5984b67ecb | ||
|
|
05fdf48058 | ||
|
|
647ed6ff82 | ||
|
|
0826b7e976 | ||
|
|
a51632cd4b | ||
|
|
bf945a7ef4 | ||
|
|
353f15e94f | ||
|
|
cf19f18662 | ||
|
|
fdb9d1cf95 | ||
|
|
2e0917428b | ||
|
|
0b16005f4b | ||
|
|
74bbe87b58 | ||
|
|
6f4131539b | ||
|
|
06283f0ffb | ||
|
|
dfe5ee43c2 | ||
|
|
eaa553dc83 | ||
|
|
83d8a2b424 | ||
|
|
4d204e4aa6 | ||
|
|
87e164e275 | ||
|
|
b63eb8d090 | ||
|
|
75119acb50 | ||
|
|
f7b3c2fbe1 | ||
|
|
b317ecfa01 | ||
|
|
7b05569ef7 | ||
|
|
e0465c6c2c | ||
|
|
9057452c86 | ||
|
|
a2f6f84bde | ||
|
|
f057abff0f | ||
|
|
c61a7d9961 | ||
|
|
9587f2eeec | ||
|
|
550784f31c | ||
|
|
11b3282b3d | ||
|
|
b2532b0798 | ||
|
|
4fc41ecb17 | ||
|
|
e52663cef6 | ||
|
|
1827be2de7 | ||
|
|
8560561ef3 | ||
|
|
2019f1fa7f | ||
|
|
9e2265d148 | ||
|
|
9d02279822 | ||
|
|
17ce06d93c | ||
|
|
7b810413fe | ||
|
|
d78c0d6c02 | ||
|
|
d248acc7d1 | ||
|
|
4c0b1f753a | ||
|
|
7bb6feda55 | ||
|
|
f8a501290a | ||
|
|
cb497c9eb5 | ||
|
|
342a37a074 | ||
|
|
c3146ec74f | ||
|
|
df16813fae | ||
|
|
8d98bbc7ba | ||
|
|
bb095697f7 | ||
|
|
cdf88c6a6a | ||
|
|
4eee2c9270 | ||
|
|
222b1401f5 | ||
|
|
fbe0bf8515 | ||
|
|
626685292c | ||
|
|
67794f5cdd | ||
|
|
2e225fb841 | ||
|
|
935523f25c | ||
|
|
3b3f7ebd3e | ||
|
|
88ecfa2992 | ||
|
|
aa70fe5c5a | ||
|
|
0c8057c668 | ||
|
|
28867646b0 | ||
|
|
ca60864021 | ||
|
|
1e4561da22 | ||
|
|
1496cc990a | ||
|
|
7bb3bf8d0e | ||
|
|
d057074f17 | ||
|
|
b724a2aa84 | ||
|
|
938ddd5356 | ||
|
|
911c37d4d8 | ||
|
|
caccccb0b5 | ||
|
|
a48f11d31b | ||
|
|
fcd93feb56 | ||
|
|
b472b23773 | ||
|
|
01c8fada1f | ||
|
|
10cd137126 | ||
|
|
809d23edae | ||
|
|
d38731bc44 | ||
|
|
64792b672d | ||
|
|
3892cc2299 | ||
|
|
5bfccaa3b6 | ||
|
|
b49b7332bb | ||
|
|
08184af737 | ||
|
|
0ef6c59385 | ||
|
|
4b0bd3b509 | ||
|
|
9a4720d180 | ||
|
|
b99646558c | ||
|
|
ee12dd9ae7 | ||
|
|
006e0f2c81 | ||
|
|
7d31299b5c | ||
|
|
fe8bf834e6 | ||
|
|
5843258e8c | ||
|
|
6cd002645e | ||
|
|
4fe0861714 | ||
|
|
fbbba061dd | ||
|
|
81f2e37ea5 | ||
|
|
66de0d3a58 | ||
|
|
beb10abbf7 | ||
|
|
d60f64761b | ||
|
|
36ac0863ad | ||
|
|
104f8e09ca | ||
|
|
cfbff008c4 | ||
|
|
5cc97c7f00 | ||
|
|
5666292496 | ||
|
|
1288cbc128 | ||
|
|
5f3aa18f38 | ||
|
|
0970ae8c31 | ||
|
|
ad23f7fb29 | ||
|
|
a4be8f316e | ||
|
|
370425578f | ||
|
|
1b76f77608 | ||
|
|
0579984355 | ||
|
|
39cf81d2ab | ||
|
|
0a203c8db9 | ||
|
|
55be4dba82 | ||
|
|
f0adf36633 | ||
|
|
24afc4f3eb | ||
|
|
2cf06af433 | ||
|
|
94be2e748b | ||
|
|
7f582e5e29 | ||
|
|
3f042c8886 | ||
|
|
6f5d818544 | ||
|
|
2ccb37cb02 | ||
|
|
cfe509a556 | ||
|
|
a46a4cac01 | ||
|
|
3ed28e534a | ||
|
|
be8dbe8804 | ||
|
|
64f7eec4e9 | ||
|
|
3a93f4a49f | ||
|
|
71958adc3d | ||
|
|
acc71550c9 | ||
|
|
3ba64412f8 | ||
|
|
90c5e5a6ad | ||
|
|
8a022ee02d | ||
|
|
6a89ea8139 | ||
|
|
90c81613ac | ||
|
|
7c62904a74 | ||
|
|
4f6344a12f | ||
|
|
937d3adf66 | ||
|
|
3bac16229f | ||
|
|
ea57847c97 | ||
|
|
730d68132d | ||
|
|
6db872236e | ||
|
|
ba7e676c6f | ||
|
|
6e99accf99 | ||
|
|
b195df9773 | ||
|
|
f303d9d7e8 | ||
|
|
62a2a2e8f9 | ||
|
|
ffbadbcc4c | ||
|
|
50ad2ee9d6 | ||
|
|
c170af5642 | ||
|
|
242bceecd3 | ||
|
|
06346b8a2a | ||
|
|
b071eeadfb | ||
|
|
e7f23d8328 | ||
|
|
47a3f09abf | ||
|
|
a7a6af0a68 | ||
|
|
f203b6c051 | ||
|
|
07211f1fc3 | ||
|
|
bc27f6c0d8 | ||
|
|
c65f9c3497 | ||
|
|
afe5f57adc | ||
|
|
9135c7ce56 | ||
|
|
7fae415689 | ||
|
|
e5cc8667ac | ||
|
|
0ea18d0e16 | ||
|
|
2d674999f0 | ||
|
|
3121903fa3 | ||
|
|
af2e49aa29 | ||
|
|
22940635fe | ||
|
|
c1042b32b7 | ||
|
|
29a144694d | ||
|
|
548d56e654 | ||
|
|
6fb4f2d6d2 | ||
|
|
8eac07ad24 | ||
|
|
716402a180 | ||
|
|
4c3d6938ed | ||
|
|
b4486802f2 | ||
|
|
d210e3d76a | ||
|
|
f2773f585e | ||
|
|
305695ad5d | ||
|
|
418ab36a72 | ||
|
|
563b4fbbd5 | ||
|
|
878d33115f | ||
|
|
356a4ee62e | ||
|
|
eb32ae25e0 | ||
|
|
3ca4062536 | ||
|
|
019f8aaf30 | ||
|
|
663fa737f3 | ||
|
|
73d86259ce | ||
|
|
c7eedf85c7 | ||
|
|
8dc3ffd552 | ||
|
|
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 |
13
.config/dotnet-tools.json
Normal file
13
.config/dotnet-tools.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"docfx": {
|
||||
"version": "2.78.3",
|
||||
"commands": [
|
||||
"docfx"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
41
.editorconfig
Normal file
41
.editorconfig
Normal file
@@ -0,0 +1,41 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker)
|
||||
spelling_exclusion_path = ./exclusion.dic
|
||||
|
||||
[*.cs]
|
||||
indent_size = 4
|
||||
charset = utf-8-bom
|
||||
end_of_line = unset
|
||||
|
||||
# Solution files
|
||||
[*.{sln,slnx}]
|
||||
end_of_line = unset
|
||||
|
||||
# MSBuild project files
|
||||
[*.{csproj,props,targets}]
|
||||
end_of_line = unset
|
||||
|
||||
# Xml config files
|
||||
[*.{ruleset,config,nuspec,resx,runsettings,DotSettings}]
|
||||
end_of_line = unset
|
||||
|
||||
[*{_AssemblyInfo.cs,.notsupported.cs}]
|
||||
generated_code = true
|
||||
|
||||
# C# code style settings
|
||||
[*.{cs}]
|
||||
dotnet_diagnostic.IDE0044.severity = none # IDE0044: Make field readonly
|
||||
|
||||
# https://stackoverflow.com/questions/79195382/how-to-disable-fading-unused-methods-in-visual-studio-2022-17-12-0
|
||||
dotnet_diagnostic.IDE0051.severity = none # IDE0051: Remove unused private member
|
||||
dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: [neuecc]
|
||||
18
.github/dependabot.yaml
vendored
Normal file
18
.github/dependabot.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# ref: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly" # Check for updates to GitHub Actions every week
|
||||
groups:
|
||||
dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact.
|
||||
ignore:
|
||||
# I just want update action when major/minor version is updated. patch updates are too noisy.
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-patch
|
||||
93
.github/workflows/build-debug.yaml
vendored
Normal file
93
.github/workflows/build-debug.yaml
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
name: Build-Debug
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
build-dotnet:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
- run: dotnet build -c Release
|
||||
- run: dotnet test -c Release
|
||||
- run: dotnet pack -c Release --no-build -p:IncludeSymbols=true -o $GITHUB_WORKSPACE/artifacts
|
||||
|
||||
build-unity:
|
||||
if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
unity: ["2022.3.39f1", "6000.0.12f1"] # Test with LTS
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30 # Unity build takes more than 20min.
|
||||
steps:
|
||||
- name: Load secrets
|
||||
id: op-load-secret
|
||||
uses: 1password/load-secrets-action@92467eb28f72e8255933372f1e0707c567ce2259 # v4.0.0
|
||||
with:
|
||||
export-env: false
|
||||
env:
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
|
||||
# Execute scripts: Export Package
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
- name: Build Unity (.unitypacakge)
|
||||
if: ${{ startsWith(matrix.unity, '2022') }} # only execute once
|
||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
||||
env:
|
||||
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
|
||||
# Execute UnitTest
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend IL2CPP /BuildTarget StandaloneLinux64
|
||||
- name: Build UnitTest (IL2CPP)
|
||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
||||
env:
|
||||
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: UnitTestBuilder.BuildUnitTest
|
||||
customParameters: "/headless /ScriptBackend IL2CPP"
|
||||
- name: Check UnitTest file is generated
|
||||
run: ls -lR ./src/UniTask/bin/UnitTest
|
||||
- name: Execute UnitTest
|
||||
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_IL2CPP/test
|
||||
|
||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
||||
with:
|
||||
directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
|
||||
if: ${{ startsWith(matrix.unity, '2021') }} # only execute 2021
|
||||
with:
|
||||
name: UniTask.unitypackage-${{ matrix.unity }}.zip
|
||||
path: ./src/UniTask/*.unitypackage
|
||||
retention-days: 1
|
||||
86
.github/workflows/build-debug.yml
vendored
86
.github/workflows/build-debug.yml
vendored
@@ -1,86 +0,0 @@
|
||||
name: Build-Debug
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
tags:
|
||||
- "!*" # not a tag push
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
build-dotnet:
|
||||
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
|
||||
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.x
|
||||
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
|
||||
|
||||
build-unity:
|
||||
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]')) && ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ["2019.3.9f1", "2019.4.13f1", "2020.1.12f1"]
|
||||
include:
|
||||
- unity: 2019.3.9f1
|
||||
license: UNITY_LICENSE_2019
|
||||
- unity: 2019.4.13f1
|
||||
license: UNITY_LICENSE_2019
|
||||
- unity: 2020.1.12f1
|
||||
license: UNITY_LICENSE_2020
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# Execute scripts: RuntimeUnitTestToolkit
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend mono /BuildTarget StandaloneLinux64
|
||||
- name: Build UnitTest(Linux64, mono)
|
||||
uses: game-ci/unity-builder@v2.0-alpha-6
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: UnitTestBuilder.BuildUnitTest
|
||||
customParameters: /headless /ScriptBackend mono
|
||||
versioning: None
|
||||
- name: Execute UnitTest
|
||||
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_Mono2x/test
|
||||
|
||||
# Execute scripts: Export Package
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
- name: Export unitypackage
|
||||
uses: game-ci/unity-builder@v2.0-alpha-6
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
versioning: None
|
||||
|
||||
- name: check all .meta is commited
|
||||
run: |
|
||||
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
|
||||
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
|
||||
exit 1
|
||||
else
|
||||
echo "Great, all .meta files are commited."
|
||||
fi
|
||||
working-directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UniTask.unitypackage-${{ matrix.unity }}.zip
|
||||
path: ./src/UniTask/*.unitypackage
|
||||
58
.github/workflows/build-docs.yaml
vendored
Normal file
58
.github/workflows/build-docs.yaml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: build-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- feature/docs
|
||||
|
||||
jobs:
|
||||
run-docfx:
|
||||
if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Load secrets
|
||||
id: op-load-secret
|
||||
uses: 1password/load-secrets-action@92467eb28f72e8255933372f1e0707c567ce2259 # v4.0.0
|
||||
with:
|
||||
export-env: false
|
||||
env:
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
# Execute scripts: Export Package
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
- name: Build Unity (.unitypackage)
|
||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
||||
env:
|
||||
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: "2022.3.39f1"
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
with:
|
||||
repository: Cysharp/DocfxTemplate
|
||||
path: docs/_DocfxTemplate
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
- name: dotnet tool restore
|
||||
run: dotnet tool restore
|
||||
- name: Docfx metadata
|
||||
run: dotnet docfx metadata docs/docfx.json
|
||||
- name: Docfx build
|
||||
run: dotnet docfx build docs/docfx.json
|
||||
- name: Publish to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: docs/_site
|
||||
31
.github/workflows/build-docs.yml
vendored
31
.github/workflows/build-docs.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: build-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- feature/docs
|
||||
|
||||
jobs:
|
||||
run-docfx:
|
||||
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: Cysharp/DocfxTemplate
|
||||
path: docs/_DocfxTemplate
|
||||
- uses: Kirbyrawr/docfx-action@master
|
||||
name: Docfx metadata
|
||||
with:
|
||||
args: metadata docs/docfx.json
|
||||
- uses: Kirbyrawr/docfx-action@master
|
||||
name: Docfx build
|
||||
with:
|
||||
args: build docs/docfx.json
|
||||
- name: Publish to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: docs/_site
|
||||
122
.github/workflows/build-release.yaml
vendored
Normal file
122
.github/workflows/build-release.yaml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
name: build-release
|
||||
|
||||
on:
|
||||
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
|
||||
|
||||
jobs:
|
||||
update-packagejson:
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
|
||||
with:
|
||||
file-path: ./src/UniTask/Assets/Plugins/UniTask/package.json
|
||||
tag: ${{ inputs.tag }}
|
||||
dry-run: ${{ inputs.dry-run }}
|
||||
|
||||
build-dotnet:
|
||||
needs: [update-packagejson]
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||
# build and pack
|
||||
- run: dotnet build -c Release -p:Version=${{ inputs.tag }}
|
||||
- run: dotnet test -c Release --no-build
|
||||
- run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish
|
||||
# Store artifacts.
|
||||
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
|
||||
with:
|
||||
name: nuget
|
||||
path: ./publish/
|
||||
retention-days: 1
|
||||
|
||||
build-unity:
|
||||
needs: [update-packagejson]
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ["2022.3.39f1"]
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Load secrets
|
||||
id: op-load-secret
|
||||
uses: 1password/load-secrets-action@92467eb28f72e8255933372f1e0707c567ce2259 # v4.0.0
|
||||
with:
|
||||
export-env: false
|
||||
env:
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
# Execute scripts: Export Package
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
- name: Build Unity (.unitypacakge)
|
||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
||||
env:
|
||||
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
|
||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
||||
with:
|
||||
directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
|
||||
with:
|
||||
name: UniTask.${{ inputs.tag }}.unitypackage
|
||||
path: ./src/UniTask/UniTask.${{ inputs.tag }}.unitypackage
|
||||
retention-days: 1
|
||||
|
||||
# release
|
||||
create-release:
|
||||
needs: [update-packagejson, build-dotnet, build-unity]
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write # required for NuGet Trusted Publish
|
||||
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
|
||||
with:
|
||||
commit-id: ${{ needs.update-packagejson.outputs.sha }}
|
||||
dry-run: ${{ inputs.dry-run }}
|
||||
tag: ${{ inputs.tag }}
|
||||
nuget-push: true
|
||||
release-upload: true
|
||||
release-asset-path: ./UniTask.${{ inputs.tag }}.unitypackage/UniTask.${{ inputs.tag }}.unitypackage
|
||||
secrets: inherit
|
||||
|
||||
cleanup:
|
||||
if: ${{ needs.update-packagejson.outputs.is-branch-created == 'true' }}
|
||||
needs: [update-packagejson, build-dotnet, build-unity]
|
||||
permissions:
|
||||
contents: write
|
||||
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
|
||||
with:
|
||||
branch: ${{ needs.update-packagejson.outputs.branch-name }}
|
||||
181
.github/workflows/build-release.yml
vendored
181
.github/workflows/build-release.yml
vendored
@@ -1,181 +0,0 @@
|
||||
name: build-release
|
||||
|
||||
on:
|
||||
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"
|
||||
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
DRY_RUN: ${{ github.event.inputs.dry_run }}
|
||||
DRY_RUN_BRANCH_PREFIX: "test_release"
|
||||
DOTNET_SDK_VERISON_3: 3.1.x
|
||||
|
||||
jobs:
|
||||
update-packagejson:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET_FILE: ./src/UniTask/Assets/Plugins/UniTask/package.json
|
||||
outputs:
|
||||
sha: ${{ steps.commit.outputs.sha }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: before
|
||||
run: cat ${{ env.TARGET_FILE}}
|
||||
- name: update package.json to version ${{ env.GIT_TAG }}
|
||||
run: sed -i -e "s/\(\"version\":\) \"\(.*\)\",/\1 \"${{ env.GIT_TAG }}\",/" ${{ env.TARGET_FILE }}
|
||||
- name: after
|
||||
run: cat ${{ env.TARGET_FILE}}
|
||||
- name: Commit files
|
||||
id: commit
|
||||
run: |
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git commit -m "feat: Update package.json to ${{ env.GIT_TAG }}" -a
|
||||
echo "::set-output name=sha::$(git rev-parse HEAD)"
|
||||
- name: check sha
|
||||
run: echo "SHA ${SHA}"
|
||||
env:
|
||||
SHA: ${{ steps.commit.outputs.sha }}
|
||||
- name: tag
|
||||
run: git tag ${{ env.GIT_TAG }}
|
||||
if: env.DRY_RUN == 'false'
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
tags: true
|
||||
if: env.DRY_RUN == 'false'
|
||||
- name: Push changes (dry_run)
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
|
||||
tags: false
|
||||
if: env.DRY_RUN == 'true'
|
||||
|
||||
build-dotnet:
|
||||
needs: [update-packagejson]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
NUGET_XMLDOC_MODE: skip
|
||||
steps:
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
|
||||
# build and pack
|
||||
- run: dotnet build -c Release -p:Version=${{ env.GIT_TAG }}
|
||||
- run: dotnet test -c Release --no-build
|
||||
- run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ env.GIT_TAG }} -o ./publish
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: nuget
|
||||
path: ./publish/
|
||||
|
||||
build-unity:
|
||||
needs: [update-packagejson]
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ["2019.3.9f1"]
|
||||
include:
|
||||
- unity: 2019.3.9f1
|
||||
license: UNITY_LICENSE_2019
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||
# Execute scripts: Export Package
|
||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
- name: Export unitypackage
|
||||
uses: game-ci/unity-builder@v2.0-alpha-6
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
with:
|
||||
projectPath: src/UniTask
|
||||
unityVersion: ${{ matrix.unity }}
|
||||
targetPlatform: StandaloneLinux64
|
||||
buildMethod: PackageExporter.Export
|
||||
versioning: None
|
||||
|
||||
- name: check all .meta is commited
|
||||
run: |
|
||||
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
|
||||
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
|
||||
exit 1
|
||||
else
|
||||
echo "Great, all .meta files are commited."
|
||||
fi
|
||||
working-directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
|
||||
|
||||
create-release:
|
||||
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
|
||||
steps:
|
||||
# setup dotnet for nuget push
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
|
||||
# Create Releases
|
||||
- uses: actions/create-release@v1
|
||||
id: create_release
|
||||
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
|
||||
|
||||
cleanup:
|
||||
if: github.event.inputs.dry_run == 'true'
|
||||
needs: [build-dotnet, build-unity]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete branch
|
||||
uses: dawidd6/action-delete-branch@v3
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
branches: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
|
||||
12
.github/workflows/prevent-github-change.yaml
vendored
Normal file
12
.github/workflows/prevent-github-change.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: Prevent github change
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/**/*.yaml"
|
||||
- ".github/**/*.yml"
|
||||
|
||||
jobs:
|
||||
detect:
|
||||
permissions:
|
||||
contents: read
|
||||
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main
|
||||
14
.github/workflows/stale.yaml
vendored
Normal file
14
.github/workflows/stale.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: "Close stale issues"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main
|
||||
24
.github/workflows/stale.yml
vendored
24
.github/workflows/stale.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: "Close stale issues"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# enable issue
|
||||
stale-issue-message: "This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
|
||||
stale-issue-label: "stale"
|
||||
# enable pr
|
||||
stale-pr-message: "This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
|
||||
stale-pr-label: "stale"
|
||||
days-before-stale: 90
|
||||
days-before-close: 7
|
||||
exempt-issue-labels: "wip"
|
||||
exempt-pr-labels: "wip"
|
||||
remove-stale-when-updated: true
|
||||
15
.github/workflows/toc.yaml
vendored
Normal file
15
.github/workflows/toc.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: TOC Generator
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'README.md'
|
||||
|
||||
jobs:
|
||||
toc:
|
||||
permissions:
|
||||
contents: write
|
||||
uses: Cysharp/Actions/.github/workflows/toc-generator.yaml@main
|
||||
with:
|
||||
TOC_TITLE: "## Table of Contents"
|
||||
secrets: inherit
|
||||
15
.github/workflows/toc.yml
vendored
15
.github/workflows/toc.yml
vendored
@@ -1,15 +0,0 @@
|
||||
name: TOC Generator
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'README.md'
|
||||
|
||||
jobs:
|
||||
generateTOC:
|
||||
name: TOC Generator
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: technote-space/toc-generator@v2.4.0
|
||||
with:
|
||||
TOC_TITLE: "## Table of Contents"
|
||||
159
.gitignore
vendored
159
.gitignore
vendored
@@ -80,7 +80,7 @@ _ReSharper*
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
# Installshield output folder
|
||||
[Ee]xpress
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
@@ -100,7 +100,19 @@ publish
|
||||
*.Publish.xml
|
||||
|
||||
# NuGet Packages Directory
|
||||
packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
# packages # upm pacakge will use Packages
|
||||
# **/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
# !**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
@@ -130,134 +142,15 @@ UpgradeLog*.XML
|
||||
Assets/WSATestCertificate.pfx
|
||||
.vs/
|
||||
|
||||
Assembly-CSharp\.csproj
|
||||
|
||||
UniRx\.Async\.csproj
|
||||
|
||||
UniRx\.Async\.Editor\.csproj
|
||||
|
||||
UniRx\.Async\.Tests\.csproj
|
||||
|
||||
UniTask\.sln
|
||||
|
||||
RuntimeUnitTestToolkit\.csproj
|
||||
|
||||
Assembly-CSharp-Editor\.csproj
|
||||
|
||||
UniRx\.Async\.unitypackage
|
||||
|
||||
UniRx.Async.Tests.Editor.csproj
|
||||
|
||||
src/UniTask/UniTask.csproj
|
||||
|
||||
src/UniTask/UniTask.Editor.csproj
|
||||
|
||||
src/UniTask/UniTask.Tests.csproj
|
||||
|
||||
src/UniTask/UniTask.Tests.Editor.csproj
|
||||
|
||||
src/UniTask/UniTask.*.unitypackage
|
||||
|
||||
src/UniTask/UniTask.Linq.csproj
|
||||
|
||||
src/UniTask/DOTween.Modules.csproj
|
||||
|
||||
src/UniTask/Unity.Addressables.csproj
|
||||
|
||||
src/UniTask/Unity.Addressables.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.Analytics.DataPrivacy.csproj
|
||||
|
||||
src/UniTask/Unity.Recorder.csproj
|
||||
|
||||
src/UniTask/Unity.Recorder.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.ResourceManager.csproj
|
||||
|
||||
src/UniTask/Unity.Rider.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.ScriptableBuildPipeline.csproj
|
||||
|
||||
src/UniTask/Unity.ScriptableBuildPipeline.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.TextMeshPro.csproj
|
||||
|
||||
src/UniTask/Unity.TextMeshPro.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.Timeline.csproj
|
||||
|
||||
src/UniTask/Unity.Timeline.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.VisualStudio.Editor.csproj
|
||||
|
||||
src/UniTask/Unity.VSCode.Editor.csproj
|
||||
|
||||
src/UniTask/UnityEditor.CacheServer.csproj
|
||||
|
||||
src/UniTask/UnityEditor.TestRunner.csproj
|
||||
|
||||
src/UniTask/UnityEditor.UI.csproj
|
||||
|
||||
src/UniTask/UnityEngine.Advertisements.csproj
|
||||
|
||||
src/UniTask/UnityEngine.Monetization.csproj
|
||||
|
||||
src/UniTask/UnityEngine.TestRunner.csproj
|
||||
|
||||
src/UniTask/UnityEngine.UI.csproj
|
||||
|
||||
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
|
||||
# Unity
|
||||
|
||||
# Unity
|
||||
.vsconfig
|
||||
src/UniTask/Library/*
|
||||
src/UniTask/Temp/*
|
||||
src/UniTask/Logs/*
|
||||
src/UniTask/[Uu]ser[Ss]ettings/
|
||||
src/UniTask/*.sln
|
||||
src/UniTask/*.csproj
|
||||
src/UniTask/*.unitypackage
|
||||
!src/UniTask/Packages/
|
||||
|
||||
27
Directory.Build.props
Normal file
27
Directory.Build.props
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)opensource.snk</AssemblyOriginatorKeyFile>
|
||||
|
||||
<!-- NuGet Package Information -->
|
||||
<IsPackable>false</IsPackable>
|
||||
<PackageVersion>$(Version)</PackageVersion>
|
||||
<Company>Cysharp</Company>
|
||||
<Authors>Cysharp</Authors>
|
||||
<Copyright>© Cysharp, Inc.</Copyright>
|
||||
<PackageTags>task;async</PackageTags>
|
||||
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageIcon>Icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="$(MSBuildThisFileDirectory)Icon.png" Pack="true" PackagePath="\" />
|
||||
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)LICENSE" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
184
README.md
184
README.md
@@ -1,6 +1,6 @@
|
||||
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 for Unity.
|
||||
|
||||
@@ -33,6 +33,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
|
||||
- [AsyncEnumerable and Async LINQ](#asyncenumerable-and-async-linq)
|
||||
- [Awaitable Events](#awaitable-events)
|
||||
- [Channel](#channel)
|
||||
- [vs Awaitable](#vs-awaitable)
|
||||
- [For Unit Testing](#for-unit-testing)
|
||||
- [ThreadPool limitation](#threadpool-limitation)
|
||||
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
||||
@@ -44,7 +45,6 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
|
||||
- [API References](#api-references)
|
||||
- [UPM Package](#upm-package)
|
||||
- [Install via git URL](#install-via-git-url)
|
||||
- [Install via OpenUPM](#install-via-openupm)
|
||||
- [.NET Core](#net-core)
|
||||
- [License](#license)
|
||||
|
||||
@@ -52,7 +52,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
|
||||
|
||||
Getting started
|
||||
---
|
||||
Install via [UPM package](#upm-package) or asset package(`UniTask.*.*.*.unitypackage`) available in [UniTask/releases](https://github.com/Cysharp/UniTask/releases) page.
|
||||
Install via [UPM package](#upm-package) with git reference or asset package(`UniTask.*.*.*.unitypackage`) available in [UniTask/releases](https://github.com/Cysharp/UniTask/releases).
|
||||
|
||||
```csharp
|
||||
// extension awaiter/methods can be used by this namespace
|
||||
@@ -68,6 +68,7 @@ async UniTask<string> DemoAsync()
|
||||
await SceneManager.LoadSceneAsync("scene2");
|
||||
|
||||
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
|
||||
// after Unity 2022.2, you can use `destroyCancellationToken` in MonoBehaviour
|
||||
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
||||
|
||||
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
||||
@@ -86,8 +87,13 @@ async UniTask<string> DemoAsync()
|
||||
await UniTask.Yield();
|
||||
await UniTask.NextFrame();
|
||||
|
||||
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
|
||||
// replacement of WaitForEndOfFrame
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
await UniTask.WaitForEndOfFrame();
|
||||
#else
|
||||
// requires MonoBehaviour(CoroutineRunner))
|
||||
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
|
||||
#endif
|
||||
|
||||
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
|
||||
await UniTask.WaitForFixedUpdate();
|
||||
@@ -156,7 +162,7 @@ UniTask provides three pattern of extension methods.
|
||||
|
||||
> 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.
|
||||
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`, `UniTask.WhenEach`. 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 async UniTaskVoid LoadManyAsync()
|
||||
@@ -241,9 +247,59 @@ CancellationToken can be created by `CancellationTokenSource` or MonoBehaviour's
|
||||
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
|
||||
```
|
||||
|
||||
When cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. `OperationCanceledException` is a special exception, if this exception is not handled, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`.
|
||||
For propagate Cancellation, all async method recommend to accept `CancellationToken cancellationToken` at last argument, and pass `CancellationToken` from root to end.
|
||||
|
||||
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.`
|
||||
```csharp
|
||||
await FooAsync(this.GetCancellationTokenOnDestroy());
|
||||
|
||||
// ---
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After Unity 2022.2, Unity adds CancellationToken in [MonoBehaviour.destroyCancellationToken](https://docs.unity3d.com/ScriptReference/MonoBehaviour-destroyCancellationToken.html) and [Application.exitCancellationToken](https://docs.unity3d.com/ScriptReference/Application-exitCancellationToken.html).
|
||||
|
||||
When cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. When exception(not limited to `OperationCanceledException`) is not handled in async method, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`. The default behaviour of received unhandled exception is to write log as exception. Log level can be changed using `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to use custom behaviour, set an action to `UniTaskScheduler.UnobservedTaskException.`
|
||||
|
||||
And also `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.
|
||||
|
||||
If you want to cancel behaviour in an async UniTask method, throw `OperationCanceledException` manually.
|
||||
|
||||
@@ -265,7 +321,7 @@ 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;
|
||||
}
|
||||
@@ -284,6 +340,18 @@ if (isCanceled)
|
||||
|
||||
Note: Only suppress throws if you call directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not suppress throws.
|
||||
|
||||
Some features that use Unity's player loop, such as `UniTask.Yield` and `UniTask.Delay` etc, determines CancellationToken state on the player loop.
|
||||
This means it does not cancel immediately upon `CancellationToken` fired.
|
||||
|
||||
If you want to change this behaviour, the cancellation to be immediate, set the `cancelImmediately` flag as an argument.
|
||||
|
||||
```csharp
|
||||
await UniTask.Yield(cancellationToken, cancelImmediately: true);
|
||||
```
|
||||
|
||||
Note: Setting `cancelImmediately` to true and detecting an immediate cancellation is more costly than the default behavior.
|
||||
This is because it uses `CancellationToken.Register`; it is heavier than checking CancellationToken on the player loop.
|
||||
|
||||
Timeout handling
|
||||
---
|
||||
Timeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.
|
||||
@@ -311,7 +379,7 @@ If you want to use timeout with other source of cancellation, use `CancellationT
|
||||
|
||||
```csharp
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
cancelButton.onClick.AddListener(()=>
|
||||
cancelButton.onClick.AddListener(() =>
|
||||
{
|
||||
cancelToken.Cancel(); // cancel from button click.
|
||||
});
|
||||
@@ -448,17 +516,22 @@ public enum PlayerLoopTiming
|
||||
|
||||
It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop.
|
||||
|
||||
`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar to `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`.
|
||||
|
||||
> `await UniTask.WaitForEndOfFrame()` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, use a coroutine instead.
|
||||
> `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.
|
||||
>
|
||||
> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`.
|
||||
|
||||
`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.
|
||||
|
||||
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and fastest.
|
||||
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and runs on YieldRunner. It is the most lightweight and fastest.
|
||||
|
||||
`AsyncOperation` is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after being called, the loaded scene's `Start` is called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||
|
||||
In UniTask, await directly uses native timing, `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
|
||||
In UniTask, await directly uses native timing, 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`.
|
||||
|
||||
> Note: When using Unity 2023.1 or newer, ensure you have `using UnityEngine;` in the using statements of your file when working with new `UnityEngine.Awaitable` methods like `SceneManager.LoadSceneAsync`.
|
||||
> This prevents compilation errors by avoiding the use of the `UnityEngine.AsyncOperation` version.
|
||||
|
||||
In the stacktrace, you can check where it is running in playerloop.
|
||||
|
||||
@@ -610,7 +683,8 @@ By default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField`
|
||||
|
||||
There are defined in separated asmdefs like `UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.
|
||||
|
||||
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager. However for DOTween support, 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.
|
||||
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager.
|
||||
However for DOTween support, after importing from the [DOTWeen assets](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676r) and define the scripting define symbol `UNITASK_DOTWEEN_SUPPORT` to enable it.
|
||||
|
||||
```csharp
|
||||
// sequential
|
||||
@@ -633,7 +707,7 @@ Unity 2020.2 supports C# 8.0 so you can use `await foreach`. This is the new Upd
|
||||
|
||||
```csharp
|
||||
// Unity 2020.2, C# 8.0
|
||||
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate(token))
|
||||
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(token))
|
||||
{
|
||||
Debug.Log("Update() " + Time.frameCount);
|
||||
}
|
||||
@@ -643,10 +717,23 @@ In a C# 7.3 environment, you can use the `ForEachAsync` method to work in almost
|
||||
|
||||
```csharp
|
||||
// C# 7.3(Unity 2018.3~)
|
||||
await UniTaskAsyncEnumerable.EveryUpdate(token).ForEachAsync(_ =>
|
||||
await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
|
||||
{
|
||||
Debug.Log("Update() " + Time.frameCount);
|
||||
});
|
||||
}, token);
|
||||
```
|
||||
|
||||
`UniTask.WhenEach` that is similar to .NET 9's `Task.WhenEach` can consume new way for await multiple tasks.
|
||||
|
||||
```csharp
|
||||
await foreach (var result in UniTask.WhenEach(task1, task2, task3))
|
||||
{
|
||||
// The result is of type WhenEachResult<T>.
|
||||
// It contains either `T Result` or `Exception Exception`.
|
||||
// You can check `IsCompletedSuccessfully` or `IsFaulted` to determine whether to access `.Result` or `.Exception`.
|
||||
// If you want to throw an exception when `IsFaulted` and retrieve the result when successful, use `GetResult()`.
|
||||
Debug.Log(result.GetResult());
|
||||
}
|
||||
```
|
||||
|
||||
UniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable<T>` or Rx in `IObservable<T>`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.
|
||||
@@ -669,7 +756,7 @@ Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAs
|
||||
|
||||
It's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.
|
||||
|
||||
`UniTaskAsyncEnumerable` is the entry point like `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`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
|
||||
`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`,`Merge` `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`.
|
||||
|
||||
@@ -757,32 +844,13 @@ async UniTask TripleClick(CancellationToken token)
|
||||
}
|
||||
```
|
||||
|
||||
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`.
|
||||
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 to uGUI event, AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.
|
||||
|
||||
```csharp
|
||||
// use await multiple times, get AsyncTriggerHandler is more efficient.
|
||||
using(var trigger = this.GetOnCollisionEnterAsyncHandler())
|
||||
{
|
||||
await OnCollisionEnterAsync();
|
||||
await OnCollisionEnterAsync();
|
||||
await OnCollisionEnterAsync();
|
||||
}
|
||||
var trigger = this.GetOnCollisionEnterAsyncHandler();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
await trigger.OnCollisionEnterAsync();
|
||||
|
||||
// every moves.
|
||||
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
||||
@@ -810,9 +878,9 @@ 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.
|
||||
@@ -848,7 +916,7 @@ button.OnClickAsAsyncEnumerable().Subscribe(async x =>
|
||||
|
||||
Channel
|
||||
---
|
||||
`Channel` is the same as [System.Threading.Tasks.Channels](https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.channels?view=netcore-3.1) which is similar to a 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 it only supports multiple-producer, single-consumer unbounded channels. It can create by `Channel.CreateSingleConsumerUnbounded<T>()`.
|
||||
|
||||
@@ -889,6 +957,14 @@ public class AsyncMessageBroker<T> : IDisposable
|
||||
}
|
||||
```
|
||||
|
||||
vs Awaitable
|
||||
---
|
||||
Unity 6 introduces the awaitable type, [Awaitable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Awaitable.html). To put it simply, Awaitable can be considered a subset of UniTask, and in fact, Awaitable's design was influenced by UniTask. It should be able to handle PlayerLoop-based awaits, pooled Tasks, and support for cancellation with `CancellationToken` in a similar way. With its inclusion in the standard library, you may wonder whether to continue using UniTask or migrate to Awaitable. Here's a brief guide.
|
||||
|
||||
First, the functionality provided by Awaitable is equivalent to what coroutines offer. Instead of `yield return`, you use await; `await NextFrameAsync()` replaces `yield return null`; and there are equivalents for `WaitForSeconds` and `EndOfFrame`. However, that's the extent of it. Being coroutine-based in terms of functionality, it lacks Task-based features. In practical application development using async/await, operations like `WhenAll` are essential. Additionally, UniTask enables many frame-based operations (such as `DelayFrame`) and more flexible PlayerLoopTiming control, which are not available in Awaitable. Of course, there's no Tracker Window either.
|
||||
|
||||
Therefore, I recommend using UniTask for application development. UniTask is a superset of Awaitable and includes many essential features. For library development, where you want to avoid external dependencies, using Awaitable as a return type for methods would be appropriate. Awaitable can be converted to UniTask using `AsUniTask`, so there's no issue in handling Awaitable-based functionality within the UniTask library. Of course, if you don't need to worry about dependencies, using UniTask would be the best choice even for library development.
|
||||
|
||||
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 methods.
|
||||
@@ -918,9 +994,9 @@ UniTask's own unit tests are written using Unity Test Runner and [Cysharp/Runtim
|
||||
|
||||
ThreadPool limitation
|
||||
---
|
||||
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run` and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
|
||||
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run`(`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` will be deprecated in the future (marked with an Obsolete) and only `RunOnThreadPool` will be used. If you use `UniTask.Run`, consider whether you can use `UniTask.Create` or `UniTask.Void`.
|
||||
`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
|
||||
---
|
||||
@@ -937,7 +1013,7 @@ UniTask can run on Unity Editor like an Editor Coroutine. However, there are som
|
||||
|
||||
* 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 does not run `EditorApplication.update`(quit on single frame) so should not use `-quit` and quit manually with `Environment.Exit(0)`.
|
||||
* `-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
|
||||
---
|
||||
@@ -975,9 +1051,10 @@ 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.WhenEach` | `UniTask.WhenEach` |
|
||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||
| `Task.FromException` | `UniTask.FromException` |
|
||||
| `Task.FromResult` | `UniTask.FromResult` |
|
||||
@@ -1043,13 +1120,6 @@ or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/
|
||||
|
||||
If you want to set a target version, UniTask uses the `*.*.*` release tag so you can specify a version like `#2.1.0`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0`.
|
||||
|
||||
### Install via OpenUPM
|
||||
|
||||
The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
|
||||
|
||||
```
|
||||
openupm add com.cysharp.unitask
|
||||
```
|
||||
|
||||
.NET Core
|
||||
---
|
||||
@@ -1059,7 +1129,7 @@ For .NET Core, use NuGet.
|
||||
|
||||
UniTask of .NET Core version is a subset of Unity UniTask with PlayerLoop dependent methods removed.
|
||||
|
||||
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AysncLocal` also does not work because it ignores ExecutionContext.
|
||||
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AsyncLocal` also does not work because it ignores ExecutionContext.
|
||||
|
||||
If you use UniTask internally, but provide ValueTask as an external API, you can write it like the following(Inspired by [PooledAwait](https://github.com/mgravell/PooledAwait)).
|
||||
|
||||
|
||||
1170
README_CN.md
Normal file
1170
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
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
"src": [
|
||||
{
|
||||
"files": [
|
||||
"UniTask/Assets/Plugins/UniTask/Runtime/**/*.cs"
|
||||
"UniTask/Library/ScriptAssemblies/UniTask*.dll"
|
||||
],
|
||||
"exclude": [
|
||||
"UniTask/Library/ScriptAssemblies/UniTask.Tests.dll",
|
||||
"UniTask/Library/ScriptAssemblies/UniTask.Tests.Editor.dll"
|
||||
],
|
||||
"src": "../src"
|
||||
}
|
||||
@@ -54,7 +58,6 @@
|
||||
}
|
||||
],
|
||||
"dest": "_site",
|
||||
|
||||
"globalMetadataFiles": [],
|
||||
"fileMetadataFiles": [],
|
||||
"template": [
|
||||
@@ -67,4 +70,4 @@
|
||||
"keepFileLink": false,
|
||||
"cleanupCacheHistory": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
opensource.snk
Normal file
BIN
opensource.snk
Normal file
Binary file not shown.
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0</TargetFrameworks>
|
||||
<AssemblyName>UniTask</AssemblyName>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0;netstandard2.1;netstandard2.0</TargetFrameworks>
|
||||
<AssemblyName>UniTask</AssemblyName>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
||||
<DefineConstants>UNITASK_NETCORE</DefineConstants>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
|
||||
<!-- NuGet Packaging -->
|
||||
<Id>UniTask</Id>
|
||||
<PackageVersion>$(Version)</PackageVersion>
|
||||
<Company>Cysharp</Company>
|
||||
<Authors>Cysharp</Authors>
|
||||
<Copyright>© Cysharp, Inc.</Copyright>
|
||||
<PackageTags>task;async</PackageTags>
|
||||
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
|
||||
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
|
||||
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageIcon>Icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
<!-- NuGet Packaging -->
|
||||
<IsPackable>true</IsPackable>
|
||||
<Id>UniTask</Id>
|
||||
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Icon.png" Pack="true" PackagePath="/" />
|
||||
</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\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>
|
||||
<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;
|
||||
" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -17,499 +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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class Foo
|
||||
{
|
||||
public async UniTask MethodFooAsync()
|
||||
{
|
||||
await MethodBarAsync();
|
||||
}
|
||||
|
||||
private async UniTask MethodBarAsync()
|
||||
|
||||
{
|
||||
Throw();
|
||||
}
|
||||
|
||||
private void Throw()
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public TestAwaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
readonly T value;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public TestAwaiter<T> GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static partial class UnityUIComponentExtensions
|
||||
{
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
|
||||
{
|
||||
AAAACORECORE(source, text).Forget();
|
||||
|
||||
async UniTaskVoid AAAACORECORE(IUniTaskAsyncEnumerable<string> source2, Text text2)
|
||||
{
|
||||
var e = source2.GetAsyncEnumerator();
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
text2.text = e.Current;
|
||||
// action(e.Current);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
|
||||
//{
|
||||
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
|
||||
//}
|
||||
|
||||
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
|
||||
//{
|
||||
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
|
||||
//}
|
||||
|
||||
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
|
||||
//{
|
||||
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
|
||||
//}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static string FlattenGenArgs(Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var t = string.Join(", ", type.GetGenericArguments().Select(x => FlattenGenArgs(x)));
|
||||
return Regex.Replace(type.Name, "`.+", "") + "<" + t + ">";
|
||||
}
|
||||
//x.ReturnType.GetGenericArguments()
|
||||
else
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
}
|
||||
|
||||
static async IAsyncEnumerable<int> FooAsync([EnumeratorCancellation]CancellationToken cancellationToken = default)
|
||||
{
|
||||
yield return 1;
|
||||
await Task.Delay(10, cancellationToken);
|
||||
}
|
||||
|
||||
public class MyDisposable : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void Test()
|
||||
{
|
||||
var disp = new MyDisposable();
|
||||
|
||||
using var _ = new MyDisposable();
|
||||
|
||||
Console.WriteLine("tako");
|
||||
}
|
||||
|
||||
|
||||
static async UniTask FooBarAsync()
|
||||
{
|
||||
await using (UniTask.ReturnToCurrentSynchronizationContext())
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static async UniTask Aaa()
|
||||
{
|
||||
await FooBarAsync();
|
||||
|
||||
Console.WriteLine("FooBarAsync End");
|
||||
}
|
||||
|
||||
static async UniTask WhereSelect()
|
||||
{
|
||||
await foreach (var item in UniTaskAsyncEnumerable.Range(1, 10)
|
||||
.SelectAwait(async x =>
|
||||
{
|
||||
await UniTask.Yield();
|
||||
return x;
|
||||
})
|
||||
.Where(x => x % 2 == 0))
|
||||
{
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
#if !DEBUG
|
||||
|
||||
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
|
||||
|
||||
var e = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Console.WriteLine($"Start {i}");
|
||||
await writer.YieldAsync(i);
|
||||
Console.WriteLine($"End {i}");
|
||||
}
|
||||
});
|
||||
|
||||
var ee = e.GetAsyncEnumerator();
|
||||
while (await ee.MoveNextAsync())
|
||||
{
|
||||
Console.WriteLine("ForEach " + ee.Current);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static async UniTask YieldCore()
|
||||
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,473 +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();
|
||||
RefNode refNode1 = new RefNode();
|
||||
RefNode refNode2 = new RefNode();
|
||||
Queue<Node> q1 = new Queue<Node>();
|
||||
Stack<Node> s1 = new Stack<Node>();
|
||||
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
|
||||
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
|
||||
static TaskPool<Node> pool;
|
||||
static TaskPoolRefNode<RefNode> poolRefNode;
|
||||
static TaskPoolEqualNull<Node> poolEqualNull;
|
||||
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
|
||||
static TaskPoolWithoutSize<Node> poolWithoutSize;
|
||||
static TaskPoolWithoutLock<Node> poolWithoutLock;
|
||||
|
||||
[Benchmark]
|
||||
public void Queue()
|
||||
{
|
||||
q1.Enqueue(node1);
|
||||
q1.Enqueue(node1);
|
||||
q1.TryDequeue(out _);
|
||||
q1.TryDequeue(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void QueueLock()
|
||||
{
|
||||
lock (q1) { q1.Enqueue(node1); }
|
||||
lock (q1) { q1.Enqueue(node1); }
|
||||
lock (q1) { q1.TryDequeue(out _); }
|
||||
lock (q1) { q1.TryDequeue(out _); }
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Stack()
|
||||
{
|
||||
s1.Push(node1);
|
||||
s1.Push(node2);
|
||||
s1.TryPop(out _);
|
||||
s1.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void StackLock()
|
||||
{
|
||||
lock (s1) { s1.Push(node1); }
|
||||
lock (s1) { s1.Push(node2); }
|
||||
lock (s1) { s1.TryPop(out _); }
|
||||
lock (s1) { s1.TryPop(out _); }
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ConcurrentQueue()
|
||||
{
|
||||
cq.Enqueue(node1);
|
||||
cq.Enqueue(node1);
|
||||
cq.TryDequeue(out _);
|
||||
cq.TryDequeue(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ConcurrentStack()
|
||||
{
|
||||
cs.Push(node1);
|
||||
cs.Push(node2);
|
||||
cs.TryPop(out _);
|
||||
cs.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPool()
|
||||
{
|
||||
pool.TryPush(node1);
|
||||
pool.TryPush(node2);
|
||||
pool.TryPop(out _);
|
||||
pool.TryPop(out _);
|
||||
}
|
||||
[Benchmark]
|
||||
public void TaskPoolRefNode()
|
||||
{
|
||||
poolRefNode.TryPush(refNode1);
|
||||
poolRefNode.TryPush(refNode2);
|
||||
poolRefNode.TryPop(out _);
|
||||
poolRefNode.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPoolEqualNull()
|
||||
{
|
||||
poolEqualNull.TryPush(node1);
|
||||
poolEqualNull.TryPush(node2);
|
||||
poolEqualNull.TryPop(out _);
|
||||
poolEqualNull.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPoolClass()
|
||||
{
|
||||
poolClass.TryPush(node1);
|
||||
poolClass.TryPush(node2);
|
||||
poolClass.TryPop(out _);
|
||||
poolClass.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPoolWithoutSize()
|
||||
{
|
||||
poolWithoutSize.TryPush(node1);
|
||||
poolWithoutSize.TryPush(node2);
|
||||
poolWithoutSize.TryPop(out _);
|
||||
poolWithoutSize.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPoolWithoutLock()
|
||||
{
|
||||
poolWithoutLock.TryPush(node1);
|
||||
poolWithoutLock.TryPush(node2);
|
||||
poolWithoutLock.TryPop(out _);
|
||||
poolWithoutLock.TryPop(out _);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Node : ITaskPoolNode<Node>
|
||||
{
|
||||
public Node NextNode { get; set; }
|
||||
}
|
||||
|
||||
public interface ITaskPoolNode<T>
|
||||
{
|
||||
T NextNode { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RefNode :ITaskPoolRefNode<RefNode>
|
||||
{
|
||||
RefNode nextNode;
|
||||
public ref RefNode NextNode => ref nextNode;
|
||||
}
|
||||
|
||||
public interface ITaskPoolRefNode<T>
|
||||
{
|
||||
ref T NextNode { get; }
|
||||
}
|
||||
|
||||
|
||||
// mutable struct, don't mark readonly.
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolWithoutLock<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
// Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
// Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPool<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolRefNode<T>
|
||||
where T : class, ITaskPoolRefNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
ref var nextNode = ref v.NextNode;
|
||||
root = nextNode;
|
||||
nextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolEqualNull<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (v != null)
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskPoolClass<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolWithoutSize<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int gate;
|
||||
T root;
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>NetCoreSandbox</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
|
||||
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace NetCoreTests.Linq
|
||||
|
||||
var ys = await Range(from, count).AsUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
xs.Should().Equal(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -57,19 +57,19 @@ namespace NetCoreTests.Linq
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100);
|
||||
list.Should().Equal(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200);
|
||||
list.Should().Equal(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200, 300);
|
||||
list.Should().Equal(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().BeEquivalentTo(100, 200, 300, 400);
|
||||
list.Should().Equal(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -144,19 +144,43 @@ namespace NetCoreTests.Linq
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100);
|
||||
list.Should().Equal(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200);
|
||||
list.Should().Equal(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200, 300);
|
||||
list.Should().Equal(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().BeEquivalentTo(100, 200, 300, 400);
|
||||
list.Should().Equal(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitForeachBreak()
|
||||
{
|
||||
var finallyCalled = false;
|
||||
var enumerable = UniTaskAsyncEnumerable.Create<int>(async (writer, _) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await writer.YieldAsync(1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
finallyCalled = true;
|
||||
}
|
||||
});
|
||||
|
||||
await foreach (var x in enumerable)
|
||||
{
|
||||
x.Should().Be(1);
|
||||
break;
|
||||
}
|
||||
finallyCalled.Should().BeTrue();
|
||||
}
|
||||
|
||||
async IAsyncEnumerable<int> Range(int from, int count)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
139
src/UniTask.NetCoreTests/Linq/Merge.cs
Normal file
139
src/UniTask.NetCoreTests/Linq/Merge.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma warning disable CS1998
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests.Linq
|
||||
{
|
||||
public class MergeTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task TwoSource()
|
||||
{
|
||||
var semaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("A1");
|
||||
semaphore.Release();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("A2");
|
||||
semaphore.Release();
|
||||
});
|
||||
|
||||
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("B1");
|
||||
await writer.YieldAsync("B2");
|
||||
semaphore.Release();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("B3");
|
||||
semaphore.Release();
|
||||
});
|
||||
|
||||
var result = await a.Merge(b).ToArrayAsync();
|
||||
result.Should().Equal("A1", "B1", "B2", "A2", "B3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ThreeSource()
|
||||
{
|
||||
var semaphore = new SemaphoreSlim(0, 1);
|
||||
|
||||
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("A1");
|
||||
semaphore.Release();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("A2");
|
||||
semaphore.Release();
|
||||
});
|
||||
|
||||
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("B1");
|
||||
await writer.YieldAsync("B2");
|
||||
semaphore.Release();
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
await writer.YieldAsync("B3");
|
||||
semaphore.Release();
|
||||
});
|
||||
|
||||
var c = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
await writer.YieldAsync("C1");
|
||||
semaphore.Release();
|
||||
});
|
||||
|
||||
var result = await a.Merge(b, c).ToArrayAsync();
|
||||
result.Should().Equal("C1", "A1", "B1", "B2", "A2", "B3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Throw()
|
||||
{
|
||||
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await writer.YieldAsync("A1");
|
||||
|
||||
});
|
||||
|
||||
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
throw new UniTaskTestException();
|
||||
});
|
||||
|
||||
var enumerator = a.Merge(b).GetAsyncEnumerator();
|
||||
(await enumerator.MoveNextAsync()).Should().Be(true);
|
||||
enumerator.Current.Should().Be("A1");
|
||||
|
||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await enumerator.MoveNextAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Cancel()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await writer.YieldAsync("A1");
|
||||
});
|
||||
|
||||
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
|
||||
{
|
||||
await writer.YieldAsync("B1");
|
||||
});
|
||||
|
||||
var enumerator = a.Merge(b).GetAsyncEnumerator(cts.Token);
|
||||
(await enumerator.MoveNextAsync()).Should().Be(true);
|
||||
enumerator.Current.Should().Be("A1");
|
||||
|
||||
cts.Cancel();
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => await enumerator.MoveNextAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,7 +39,7 @@ 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]
|
||||
@@ -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()
|
||||
{
|
||||
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
|
||||
foo.Should().Equal(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
@@ -116,7 +116,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()
|
||||
{
|
||||
@@ -145,7 +145,7 @@ namespace NetCoreTests.Linq
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
|
||||
foo.Should().Equal(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
|
||||
45
src/UniTask.NetCoreTests/TaskExtensionsTest.cs
Normal file
45
src/UniTask.NetCoreTests/TaskExtensionsTest.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma warning disable CS1998
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class TaskExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task PropagateException()
|
||||
{
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await ThrowAsync().AsUniTask();
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await ThrowOrValueAsync().AsUniTask();
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PropagateExceptionWhenAll()
|
||||
{
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await Task.WhenAll(ThrowAsync(), ThrowAsync()).AsUniTask();
|
||||
});
|
||||
}
|
||||
|
||||
async Task ThrowAsync()
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
async Task<int> ThrowOrValueAsync()
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RootNamespace>NetCoreTests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
80
src/UniTask.NetCoreTests/UniTaskCompletionSourceTest.cs
Normal file
80
src/UniTask.NetCoreTests/UniTaskCompletionSourceTest.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using NetCoreTests.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class AutoResetUniTaskCompletionSourceTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task SetResultAfterReturn()
|
||||
{
|
||||
var source1 = AutoResetUniTaskCompletionSource.Create();
|
||||
source1.TrySetResult();
|
||||
await source1.Task;
|
||||
|
||||
source1.TrySetResult().Should().BeFalse();
|
||||
|
||||
var source2 = AutoResetUniTaskCompletionSource.Create();
|
||||
source2.TrySetResult();
|
||||
await source2.Task;
|
||||
|
||||
source2.TrySetResult().Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetCancelAfterReturn()
|
||||
{
|
||||
var source = AutoResetUniTaskCompletionSource.Create();
|
||||
source.TrySetResult();
|
||||
await source.Task;
|
||||
|
||||
source.TrySetCanceled().Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetExceptionAfterReturn()
|
||||
{
|
||||
var source = AutoResetUniTaskCompletionSource.Create();
|
||||
source.TrySetResult();
|
||||
await source.Task;
|
||||
|
||||
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetResultWithValueAfterReturn()
|
||||
{
|
||||
var source1 = AutoResetUniTaskCompletionSource<int>.Create();
|
||||
source1.TrySetResult(100);
|
||||
(await source1.Task).Should().Be(100);
|
||||
|
||||
source1.TrySetResult(100).Should().BeFalse();
|
||||
|
||||
var source2 = AutoResetUniTaskCompletionSource.Create();
|
||||
source2.TrySetResult();
|
||||
await source2.Task;
|
||||
source2.TrySetResult().Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetCancelWithValueAfterReturn()
|
||||
{
|
||||
var source = AutoResetUniTaskCompletionSource<int>.Create();
|
||||
source.TrySetResult(100);
|
||||
(await source.Task).Should().Be(100);
|
||||
source.TrySetCanceled().Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetExceptionWithValueAfterReturn()
|
||||
{
|
||||
var source = AutoResetUniTaskCompletionSource<int>.Create();
|
||||
source.TrySetResult(100);
|
||||
(await source.Task).Should().Be(100);
|
||||
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal file
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class WhenEachTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Each()
|
||||
{
|
||||
var a = Delay(1, 3000);
|
||||
var b = Delay(2, 1000);
|
||||
var c = Delay(3, 2000);
|
||||
|
||||
var l = new List<int>();
|
||||
await foreach (var item in UniTask.WhenEach(a, b, c))
|
||||
{
|
||||
l.Add(item.Result);
|
||||
}
|
||||
|
||||
l.Should().Equal(2, 3, 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Error()
|
||||
{
|
||||
var a = Delay2(1, 3000);
|
||||
var b = Delay2(2, 1000);
|
||||
var c = Delay2(3, 2000);
|
||||
|
||||
var l = new List<WhenEachResult<int>>();
|
||||
await foreach (var item in UniTask.WhenEach(a, b, c))
|
||||
{
|
||||
l.Add(item);
|
||||
}
|
||||
|
||||
l[0].IsCompletedSuccessfully.Should().BeTrue();
|
||||
l[0].IsFaulted.Should().BeFalse();
|
||||
l[0].Result.Should().Be(2);
|
||||
|
||||
l[1].IsCompletedSuccessfully.Should().BeFalse();
|
||||
l[1].IsFaulted.Should().BeTrue();
|
||||
l[1].Exception.Message.Should().Be("ERROR");
|
||||
|
||||
l[2].IsCompletedSuccessfully.Should().BeTrue();
|
||||
l[2].IsFaulted.Should().BeFalse();
|
||||
l[2].Result.Should().Be(1);
|
||||
}
|
||||
|
||||
async UniTask<int> Delay(int id, int sleep)
|
||||
{
|
||||
await Task.Delay(sleep);
|
||||
return id;
|
||||
}
|
||||
|
||||
async UniTask<int> Delay2(int id, int sleep)
|
||||
{
|
||||
await Task.Delay(sleep);
|
||||
if (id == 3) throw new Exception("ERROR");
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,9 @@ public static class EditorRunnerChecker
|
||||
|
||||
//var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
|
||||
//Debug.Log(r.downloadHandler.text.Substring(0, 100));
|
||||
await UniTask.Yield();
|
||||
//await UniTask.Yield();
|
||||
|
||||
await UniTask.DelayFrame(30);
|
||||
|
||||
Debug.Log("End");
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
@@ -20,12 +21,12 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||
{
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCanceled: autoReleaseWhenCanceled);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
|
||||
@@ -44,7 +45,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
|
||||
}
|
||||
|
||||
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
||||
@@ -103,20 +104,23 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle> continuationAction;
|
||||
readonly Action<AsyncOperationHandle> completedCallback;
|
||||
AsyncOperationHandle handle;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
IProgress<float> progress;
|
||||
bool autoReleaseWhenCanceled;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
completedCallback = HandleCompleted;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCanceled, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -131,47 +135,81 @@ namespace Cysharp.Threading.Tasks
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
|
||||
result.completed = false;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (AsyncOperationHandleConfiguredSource)state;
|
||||
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
|
||||
{
|
||||
Addressables.Release(promise.handle);
|
||||
}
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
handle.Completed += result.completedCallback;
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperationHandle _)
|
||||
void HandleCompleted(AsyncOperationHandle _)
|
||||
{
|
||||
handle.Completed -= continuationAction;
|
||||
if (handle.IsValid())
|
||||
{
|
||||
handle.Completed -= completedCallback;
|
||||
}
|
||||
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return;
|
||||
}
|
||||
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
@@ -193,20 +231,23 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completed = true;
|
||||
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
progress.Report(handle.GetDownloadStatus().Percent);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -219,6 +260,7 @@ namespace Cysharp.Threading.Tasks
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -232,12 +274,12 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||
{
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCanceled: autoReleaseWhenCanceled);
|
||||
}
|
||||
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
||||
|
||||
@@ -255,7 +297,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return UniTask.FromResult(handle.Result);
|
||||
}
|
||||
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
@@ -269,20 +311,23 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
||||
readonly Action<AsyncOperationHandle<T>> completedCallback;
|
||||
AsyncOperationHandle<T> handle;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
IProgress<float> progress;
|
||||
bool autoReleaseWhenCanceled;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
completedCallback = HandleCompleted;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCanceled, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -298,46 +343,79 @@ namespace Cysharp.Threading.Tasks
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
result.progress = progress;
|
||||
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (AsyncOperationHandleConfiguredSource<T>)state;
|
||||
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
|
||||
{
|
||||
Addressables.Release(promise.handle);
|
||||
}
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
handle.Completed += result.completedCallback;
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperationHandle<T> argHandle)
|
||||
void HandleCompleted(AsyncOperationHandle<T> argHandle)
|
||||
{
|
||||
handle.Completed -= continuationAction;
|
||||
if (handle.IsValid())
|
||||
{
|
||||
handle.Completed -= completedCallback;
|
||||
}
|
||||
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(argHandle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(argHandle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(argHandle.Result);
|
||||
}
|
||||
core.TrySetResult(argHandle.Result);
|
||||
}
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
return core.GetResult(token);
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
@@ -364,20 +442,23 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completed = true;
|
||||
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
progress.Report(handle.GetDownloadStatus().Percent);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -390,6 +471,7 @@ namespace Cysharp.Threading.Tasks
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"name": "UniTask.Addressables",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"Unity.ResourceManager"
|
||||
"Unity.ResourceManager",
|
||||
"Unity.Addressables"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
@@ -16,7 +17,12 @@
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.addressables.cn",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace Cysharp.Threading.Tasks
|
||||
Kill,
|
||||
KillWithCompleteCallback,
|
||||
Complete,
|
||||
CompleteWithSeqeunceCallback,
|
||||
CompleteWithSequenceCallback,
|
||||
CancelAwait,
|
||||
|
||||
// AndCancelAwait
|
||||
KillAndCancelAwait,
|
||||
KillWithCompleteCallbackAndCancelAwait,
|
||||
CompleteAndCancelAwait,
|
||||
CompleteWithSeqeunceCallbackAndCancelAwait
|
||||
CompleteWithSequenceCallbackAndCancelAwait
|
||||
}
|
||||
|
||||
public static class DOTweenAsyncExtensions
|
||||
@@ -143,24 +143,21 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||
|
||||
readonly TweenCallback onCompleteCallbackDelegate;
|
||||
readonly TweenCallback onUpdateDelegate;
|
||||
|
||||
Tween tween;
|
||||
TweenCancelBehaviour cancelBehaviour;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationRegistration;
|
||||
CallbackType callbackType;
|
||||
bool canceled;
|
||||
|
||||
TweenCallback originalUpdateAction;
|
||||
TweenCallback originalCompleteAction;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
TweenConfiguredSource()
|
||||
{
|
||||
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
|
||||
onUpdateDelegate = OnUpdate;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
|
||||
@@ -180,41 +177,87 @@ namespace Cysharp.Threading.Tasks
|
||||
result.cancelBehaviour = cancelBehaviour;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.callbackType = callbackType;
|
||||
|
||||
result.originalUpdateAction = tween.onUpdate;
|
||||
result.canceled = false;
|
||||
|
||||
if (result.originalUpdateAction == result.onUpdateDelegate)
|
||||
{
|
||||
result.originalUpdateAction = null;
|
||||
}
|
||||
|
||||
tween.onUpdate = result.onUpdateDelegate;
|
||||
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
result.originalCompleteAction = tween.onKill;
|
||||
tween.onKill = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
result.originalCompleteAction = tween.onComplete;
|
||||
tween.onComplete = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
result.originalCompleteAction = tween.onPause;
|
||||
tween.onPause = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
result.originalCompleteAction = tween.onPlay;
|
||||
tween.onPlay = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
result.originalCompleteAction = tween.onRewind;
|
||||
tween.onRewind = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
result.originalCompleteAction = tween.onStepComplete;
|
||||
tween.onStepComplete = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.originalCompleteAction == result.onCompleteCallbackDelegate)
|
||||
{
|
||||
result.originalCompleteAction = null;
|
||||
}
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(x =>
|
||||
{
|
||||
var source = (TweenConfiguredSource)x;
|
||||
switch (source.cancelBehaviour)
|
||||
{
|
||||
case TweenCancelBehaviour.Kill:
|
||||
default:
|
||||
source.tween.Kill(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillAndCancelAwait:
|
||||
source.canceled = true;
|
||||
source.tween.Kill(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillWithCompleteCallback:
|
||||
source.tween.Kill(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
|
||||
source.canceled = true;
|
||||
source.tween.Kill(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.Complete:
|
||||
source.tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
||||
source.canceled = true;
|
||||
source.tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallback:
|
||||
source.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
|
||||
source.canceled = true;
|
||||
source.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
source.RestoreOriginalCallback();
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
break;
|
||||
}
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
token = result.core.Version;
|
||||
@@ -228,7 +271,7 @@ namespace Cysharp.Threading.Tasks
|
||||
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|
||||
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
|
||||
{
|
||||
canceled = true;
|
||||
@@ -240,81 +283,11 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
originalCompleteAction?.Invoke();
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
|
||||
void OnUpdate()
|
||||
{
|
||||
originalUpdateAction?.Invoke();
|
||||
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.cancelBehaviour)
|
||||
{
|
||||
case TweenCancelBehaviour.Kill:
|
||||
default:
|
||||
this.tween.Kill(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillAndCancelAwait:
|
||||
this.canceled = true;
|
||||
this.tween.Kill(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillWithCompleteCallback:
|
||||
this.tween.Kill(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
|
||||
this.canceled = true;
|
||||
this.tween.Kill(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.Complete:
|
||||
this.tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteAndCancelAwait:
|
||||
this.canceled = true;
|
||||
this.tween.Complete(false);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
|
||||
this.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
|
||||
this.canceled = true;
|
||||
this.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
// replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = EmptyTweenCallback;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.core.TrySetCanceled(this.cancellationToken);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
|
||||
{
|
||||
|
||||
@@ -339,10 +312,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:
|
||||
@@ -381,36 +354,41 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
tween.onUpdate = originalUpdateAction;
|
||||
cancellationRegistration.Dispose();
|
||||
|
||||
RestoreOriginalCallback();
|
||||
|
||||
tween = default;
|
||||
cancellationToken = default;
|
||||
originalCompleteAction = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void RestoreOriginalCallback()
|
||||
{
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = null;
|
||||
tween.onKill = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = null;
|
||||
tween.onComplete = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = null;
|
||||
tween.onPause = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = null;
|
||||
tween.onPlay = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = null;
|
||||
tween.onRewind = originalCompleteAction;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = null;
|
||||
tween.onStepComplete = originalCompleteAction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tween = default;
|
||||
cancellationToken = default;
|
||||
originalUpdateAction = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.ugui",
|
||||
"expression": "2.0.0",
|
||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS0108
|
||||
|
||||
#if (UNITASK_NETCORE && !NETSTANDARD2_0) || UNITY_2022_3_OR_NEWER
|
||||
#define SUPPORT_VALUETASK
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -19,9 +24,8 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
// similar as IValueTaskSource
|
||||
public interface IUniTaskSource
|
||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
||||
#if SUPPORT_VALUETASK
|
||||
: System.Threading.Tasks.Sources.IValueTaskSource
|
||||
#pragma warning disable CS0108
|
||||
#endif
|
||||
{
|
||||
UniTaskStatus GetStatus(short token);
|
||||
@@ -30,8 +34,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
UniTaskStatus UnsafeGetStatus(); // only for debug use.
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
||||
#pragma warning restore CS0108
|
||||
#if SUPPORT_VALUETASK
|
||||
|
||||
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
|
||||
{
|
||||
@@ -53,13 +56,13 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
public interface IUniTaskSource<out T> : IUniTaskSource
|
||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
||||
#if SUPPORT_VALUETASK
|
||||
, System.Threading.Tasks.Sources.IValueTaskSource<T>
|
||||
#endif
|
||||
{
|
||||
new T GetResult(short token);
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
|
||||
#if SUPPORT_VALUETASK
|
||||
|
||||
new public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void ThrowArgumentException<T>(string message)
|
||||
public static void ThrowArgumentException(string message)
|
||||
{
|
||||
throw new ArgumentException(message);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
writer.Dispose();
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -127,7 +128,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
|
||||
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>, IDisposable
|
||||
{
|
||||
readonly _Create enumerator;
|
||||
|
||||
@@ -137,6 +138,15 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var status = core.GetStatus(core.Version);
|
||||
if (status == UniTaskStatus.Pending)
|
||||
{
|
||||
core.TrySetCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
|
||||
234
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Merge.cs
Normal file
234
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Merge.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return new Merge<T>(new [] { first, second });
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second, IUniTaskAsyncEnumerable<T> third)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(third, nameof(third));
|
||||
|
||||
return new Merge<T>(new[] { first, second, third });
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
|
||||
{
|
||||
return sources is IUniTaskAsyncEnumerable<T>[] array
|
||||
? new Merge<T>(array)
|
||||
: new Merge<T>(sources.ToArray());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<T> Merge<T>(params IUniTaskAsyncEnumerable<T>[] sources)
|
||||
{
|
||||
return new Merge<T>(sources);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Merge<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<T>[] sources;
|
||||
|
||||
public Merge(IUniTaskAsyncEnumerable<T>[] sources)
|
||||
{
|
||||
if (sources.Length <= 0)
|
||||
{
|
||||
Error.ThrowArgumentException("No source async enumerable to merge");
|
||||
}
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
=> new _Merge(sources, cancellationToken);
|
||||
|
||||
enum MergeSourceState
|
||||
{
|
||||
Pending,
|
||||
Running,
|
||||
Completed,
|
||||
}
|
||||
|
||||
sealed class _Merge : MoveNextSource, IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
static readonly Action<object> GetResultAtAction = GetResultAt;
|
||||
|
||||
readonly int length;
|
||||
readonly IUniTaskAsyncEnumerator<T>[] enumerators;
|
||||
readonly MergeSourceState[] states;
|
||||
readonly Queue<(T, Exception, bool)> queuedResult = new Queue<(T, Exception, bool)>();
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
int moveNextCompleted;
|
||||
|
||||
public T Current { get; private set; }
|
||||
|
||||
public _Merge(IUniTaskAsyncEnumerable<T>[] sources, CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
length = sources.Length;
|
||||
states = ArrayPool<MergeSourceState>.Shared.Rent(length);
|
||||
enumerators = ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Rent(length);
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
enumerators[i] = sources[i].GetAsyncEnumerator(cancellationToken);
|
||||
states[i] = (int)MergeSourceState.Pending;;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
Interlocked.Exchange(ref moveNextCompleted, 0);
|
||||
|
||||
if (HasQueuedResult() && Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
|
||||
{
|
||||
(T, Exception, bool) value;
|
||||
lock (states)
|
||||
{
|
||||
value = queuedResult.Dequeue();
|
||||
}
|
||||
var resultValue = value.Item1;
|
||||
var exception = value.Item2;
|
||||
var hasNext = value.Item3;
|
||||
if (exception != null)
|
||||
{
|
||||
completionSource.TrySetException(exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
Current = resultValue;
|
||||
completionSource.TrySetResult(hasNext);
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
lock (states)
|
||||
{
|
||||
if (states[i] == MergeSourceState.Pending)
|
||||
{
|
||||
states[i] = MergeSourceState.Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var awaiter = enumerators[i].MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
GetResultAt(i, awaiter);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(GetResultAtAction, StateTuple.Create(this, i, awaiter));
|
||||
}
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
await enumerators[i].DisposeAsync();
|
||||
}
|
||||
|
||||
ArrayPool<MergeSourceState>.Shared.Return(states, true);
|
||||
ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Return(enumerators, true);
|
||||
}
|
||||
|
||||
static void GetResultAt(object state)
|
||||
{
|
||||
using (var tuple = (StateTuple<_Merge, int, UniTask<bool>.Awaiter>)state)
|
||||
{
|
||||
tuple.Item1.GetResultAt(tuple.Item2, tuple.Item3);
|
||||
}
|
||||
}
|
||||
|
||||
void GetResultAt(int index, UniTask<bool>.Awaiter awaiter)
|
||||
{
|
||||
bool hasNext;
|
||||
bool completedAll;
|
||||
try
|
||||
{
|
||||
hasNext = awaiter.GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (states)
|
||||
{
|
||||
queuedResult.Enqueue((default, ex, default));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
lock (states)
|
||||
{
|
||||
states[index] = hasNext ? MergeSourceState.Pending : MergeSourceState.Completed;
|
||||
completedAll = !hasNext && IsCompletedAll();
|
||||
}
|
||||
if (hasNext || completedAll)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
|
||||
{
|
||||
Current = enumerators[index].Current;
|
||||
completionSource.TrySetResult(!completedAll);
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (states)
|
||||
{
|
||||
queuedResult.Enqueue((enumerators[index].Current, null, !completedAll));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HasQueuedResult()
|
||||
{
|
||||
lock (states)
|
||||
{
|
||||
return queuedResult.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCompletedAll()
|
||||
{
|
||||
lock (states)
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
if (states[i] != MergeSourceState.Completed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca56812f160c45d0bacb4339819edf1a
|
||||
timeCreated: 1694133666
|
||||
@@ -4,38 +4,50 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
|
||||
{
|
||||
return new EveryUpdate(updateTiming);
|
||||
return new EveryUpdate(updateTiming, cancelImmediately);
|
||||
}
|
||||
}
|
||||
|
||||
internal class EveryUpdate : IUniTaskAsyncEnumerable<AsyncUnit>
|
||||
{
|
||||
readonly PlayerLoopTiming updateTiming;
|
||||
readonly bool cancelImmediately;
|
||||
|
||||
public EveryUpdate(PlayerLoopTiming updateTiming)
|
||||
public EveryUpdate(PlayerLoopTiming updateTiming, bool cancelImmediately)
|
||||
{
|
||||
this.updateTiming = updateTiming;
|
||||
this.cancelImmediately = cancelImmediately;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _EveryUpdate(updateTiming, cancellationToken);
|
||||
return new _EveryUpdate(updateTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
class _EveryUpdate : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
|
||||
{
|
||||
readonly PlayerLoopTiming updateTiming;
|
||||
CancellationToken cancellationToken;
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||
|
||||
bool disposed;
|
||||
|
||||
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
|
||||
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
this.updateTiming = updateTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (_EveryUpdate)state;
|
||||
source.completionSource.TrySetCanceled(source.cancellationToken);
|
||||
}, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
}
|
||||
@@ -44,10 +56,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
// return false instead of throw
|
||||
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
|
||||
|
||||
if (disposed) return CompletedTasks.False;
|
||||
|
||||
completionSource.Reset();
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -55,6 +71,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
cancellationTokenRegistration.Dispose();
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
@@ -63,7 +80,13 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (disposed)
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return false;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null)
|
||||
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null, bool cancelImmediately = false)
|
||||
where TTarget : class
|
||||
{
|
||||
var unityObject = target as UnityEngine.Object;
|
||||
@@ -15,11 +15,11 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
if (isUnityObject)
|
||||
{
|
||||
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
|
||||
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
|
||||
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,18 +30,20 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly Func<TTarget, TProperty> propertySelector;
|
||||
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||
readonly PlayerLoopTiming monitorTiming;
|
||||
readonly bool cancelImmediately;
|
||||
|
||||
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
|
||||
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
|
||||
{
|
||||
this.target = target;
|
||||
this.propertySelector = propertySelector;
|
||||
this.equalityComparer = equalityComparer;
|
||||
this.monitorTiming = monitorTiming;
|
||||
this.cancelImmediately = cancelImmediately;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
|
||||
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
|
||||
@@ -50,13 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly UnityEngine.Object targetAsUnityObject;
|
||||
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||
readonly Func<TTarget, TProperty> propertySelector;
|
||||
CancellationToken cancellationToken;
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||
|
||||
bool first;
|
||||
TProperty currentValue;
|
||||
bool disposed;
|
||||
|
||||
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
|
||||
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
this.target = target;
|
||||
this.targetAsUnityObject = target as UnityEngine.Object;
|
||||
@@ -64,6 +67,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.equalityComparer = equalityComparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.first = true;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (_EveryValueChanged)state;
|
||||
source.completionSource.TrySetCanceled(source.cancellationToken);
|
||||
}, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(monitorTiming, this);
|
||||
}
|
||||
@@ -72,8 +85,15 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
// return false instead of throw
|
||||
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
|
||||
if (disposed) return CompletedTasks.False;
|
||||
|
||||
completionSource.Reset();
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
@@ -86,7 +106,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -94,6 +113,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
cancellationTokenRegistration.Dispose();
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
@@ -102,13 +122,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
|
||||
if (disposed || targetAsUnityObject == null)
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
DisposeAsync().Forget();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
TProperty nextValue = default(TProperty);
|
||||
try
|
||||
{
|
||||
@@ -139,18 +164,20 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly Func<TTarget, TProperty> propertySelector;
|
||||
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||
readonly PlayerLoopTiming monitorTiming;
|
||||
readonly bool cancelImmediately;
|
||||
|
||||
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
|
||||
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
|
||||
{
|
||||
this.target = new WeakReference<TTarget>(target, false);
|
||||
this.propertySelector = propertySelector;
|
||||
this.equalityComparer = equalityComparer;
|
||||
this.monitorTiming = monitorTiming;
|
||||
this.cancelImmediately = cancelImmediately;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
|
||||
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
|
||||
@@ -158,19 +185,30 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly WeakReference<TTarget> target;
|
||||
readonly IEqualityComparer<TProperty> equalityComparer;
|
||||
readonly Func<TTarget, TProperty> propertySelector;
|
||||
CancellationToken cancellationToken;
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||
|
||||
bool first;
|
||||
TProperty currentValue;
|
||||
bool disposed;
|
||||
|
||||
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
|
||||
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
this.target = target;
|
||||
this.propertySelector = propertySelector;
|
||||
this.equalityComparer = equalityComparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.first = true;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (_EveryValueChanged)state;
|
||||
source.completionSource.TrySetCanceled(source.cancellationToken);
|
||||
}, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(monitorTiming, this);
|
||||
}
|
||||
@@ -179,8 +217,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
|
||||
if (disposed) return CompletedTasks.False;
|
||||
|
||||
completionSource.Reset();
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
@@ -192,7 +238,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -200,6 +245,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
cancellationTokenRegistration.Dispose();
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
@@ -208,13 +254,19 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
||||
if (disposed || !target.TryGetTarget(out var t))
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
DisposeAsync().Forget();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
TProperty nextValue = default(TProperty);
|
||||
try
|
||||
{
|
||||
|
||||
@@ -6,32 +6,32 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
|
||||
{
|
||||
return new Timer(dueTime, null, updateTiming, ignoreTimeScale);
|
||||
return new Timer(dueTime, null, updateTiming, ignoreTimeScale, cancelImmediately);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
|
||||
{
|
||||
return new Timer(dueTime, period, updateTiming, ignoreTimeScale);
|
||||
return new Timer(dueTime, period, updateTiming, ignoreTimeScale, cancelImmediately);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
|
||||
{
|
||||
return new Timer(period, period, updateTiming, ignoreTimeScale);
|
||||
return new Timer(period, period, updateTiming, ignoreTimeScale, cancelImmediately);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
|
||||
{
|
||||
if (dueTimeFrameCount < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
|
||||
}
|
||||
|
||||
return new TimerFrame(dueTimeFrameCount, null, updateTiming);
|
||||
return new TimerFrame(dueTimeFrameCount, null, updateTiming, cancelImmediately);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
|
||||
{
|
||||
if (dueTimeFrameCount < 0)
|
||||
{
|
||||
@@ -42,16 +42,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount);
|
||||
}
|
||||
|
||||
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming);
|
||||
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancelImmediately);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
|
||||
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
|
||||
{
|
||||
if (intervalFrameCount < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus intervalFrameCount. intervalFrameCount:" + intervalFrameCount);
|
||||
}
|
||||
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming);
|
||||
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming, cancelImmediately);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,18 +61,20 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly TimeSpan dueTime;
|
||||
readonly TimeSpan? period;
|
||||
readonly bool ignoreTimeScale;
|
||||
readonly bool cancelImmediately;
|
||||
|
||||
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale)
|
||||
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, bool cancelImmediately)
|
||||
{
|
||||
this.updateTiming = updateTiming;
|
||||
this.dueTime = dueTime;
|
||||
this.period = period;
|
||||
this.ignoreTimeScale = ignoreTimeScale;
|
||||
this.cancelImmediately = cancelImmediately;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken);
|
||||
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
class _Timer : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
|
||||
@@ -81,7 +83,8 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly float? period;
|
||||
readonly PlayerLoopTiming updateTiming;
|
||||
readonly bool ignoreTimeScale;
|
||||
CancellationToken cancellationToken;
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||
|
||||
int initialFrame;
|
||||
float elapsed;
|
||||
@@ -89,7 +92,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
bool completed;
|
||||
bool disposed;
|
||||
|
||||
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken)
|
||||
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
this.dueTime = (float)dueTime.TotalSeconds;
|
||||
this.period = (period == null) ? null : (float?)period.Value.TotalSeconds;
|
||||
@@ -105,6 +108,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.updateTiming = updateTiming;
|
||||
this.ignoreTimeScale = ignoreTimeScale;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (_Timer)state;
|
||||
source.completionSource.TrySetCanceled(source.cancellationToken);
|
||||
}, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
}
|
||||
@@ -114,12 +127,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
// return false instead of throw
|
||||
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
|
||||
if (disposed || completed) return CompletedTasks.False;
|
||||
|
||||
// reset value here.
|
||||
this.elapsed = 0;
|
||||
|
||||
completionSource.Reset();
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -127,6 +144,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
cancellationTokenRegistration.Dispose();
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
@@ -135,11 +153,16 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested)
|
||||
if (disposed)
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return false;
|
||||
}
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dueTimePhase)
|
||||
{
|
||||
@@ -187,24 +210,27 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
readonly PlayerLoopTiming updateTiming;
|
||||
readonly int dueTimeFrameCount;
|
||||
readonly int? periodFrameCount;
|
||||
readonly bool cancelImmediately;
|
||||
|
||||
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming)
|
||||
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, bool cancelImmediately)
|
||||
{
|
||||
this.updateTiming = updateTiming;
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
this.cancelImmediately = cancelImmediately;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken);
|
||||
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
|
||||
{
|
||||
readonly int dueTimeFrameCount;
|
||||
readonly int? periodFrameCount;
|
||||
CancellationToken cancellationToken;
|
||||
readonly CancellationToken cancellationToken;
|
||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||
|
||||
int initialFrame;
|
||||
int currentFrame;
|
||||
@@ -212,7 +238,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
bool completed;
|
||||
bool disposed;
|
||||
|
||||
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
|
||||
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
|
||||
if (periodFrameCount != null)
|
||||
@@ -225,6 +251,15 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (_TimerFrame)state;
|
||||
source.completionSource.TrySetCanceled(source.cancellationToken);
|
||||
}, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
@@ -234,13 +269,15 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
// return false instead of throw
|
||||
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
|
||||
if (disposed || completed) return CompletedTasks.False;
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
// reset value here.
|
||||
this.currentFrame = 0;
|
||||
|
||||
completionSource.Reset();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
@@ -249,6 +286,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
cancellationTokenRegistration.Dispose();
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
@@ -257,7 +295,12 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed || cancellationToken.IsCancellationRequested)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
if (disposed)
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return false;
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace Cysharp.Threading.Tasks
|
||||
static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
|
||||
static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
|
||||
|
||||
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext;
|
||||
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;
|
||||
public static int MainThreadId => mainThreadId;
|
||||
internal static string ApplicationDataPath => applicationDataPath;
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
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; }
|
||||
@@ -285,11 +285,15 @@ namespace Cysharp.Threading.Tasks
|
||||
return dest.ToArray();
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
static void Init()
|
||||
{
|
||||
// capture default(unity) sync-context.
|
||||
unitySynchronizationContetext = SynchronizationContext.Current;
|
||||
unitySynchronizationContext = SynchronizationContext.Current;
|
||||
mainThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
try
|
||||
{
|
||||
@@ -524,6 +528,14 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
sb.AppendFormat("------{0}------", header.type.Name);
|
||||
sb.AppendLine();
|
||||
|
||||
if (header.subSystemList is null)
|
||||
{
|
||||
sb.AppendFormat("{0} has no subsystems!", header.ToString());
|
||||
sb.AppendLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var subSystem in header.subSystemList)
|
||||
{
|
||||
sb.AppendFormat("{0}", subSystem.type.Name);
|
||||
@@ -545,6 +557,11 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
foreach (var header in playerLoop.subSystemList)
|
||||
{
|
||||
if (header.subSystemList is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var subSystem in header.subSystemList)
|
||||
{
|
||||
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
|
||||
|
||||
@@ -7,7 +7,7 @@ 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
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
timer.Stop();
|
||||
timer?.Stop();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -109,7 +109,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
// stop timer.
|
||||
timer.Dispose();
|
||||
timer?.Dispose();
|
||||
|
||||
// cancel and dispose.
|
||||
timeoutSource.Cancel();
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
ITriggerHandler<T> head; // head.prev is last
|
||||
ITriggerHandler<T> iteratingHead;
|
||||
|
||||
bool preserveRemoveSelf;
|
||||
ITriggerHandler<T> iteratingNode;
|
||||
|
||||
void LogError(Exception ex)
|
||||
@@ -55,18 +53,9 @@ namespace Cysharp.Threading.Tasks
|
||||
Remove(h);
|
||||
}
|
||||
|
||||
if (preserveRemoveSelf)
|
||||
{
|
||||
preserveRemoveSelf = false;
|
||||
iteratingNode = null;
|
||||
var next = h.Next;
|
||||
Remove(h);
|
||||
h = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = h.Next;
|
||||
}
|
||||
// If `h` itself is removed by OnNext, h.Next is null.
|
||||
// Therefore, instead of looking at h.Next, the `iteratingNode` reference itself is replaced.
|
||||
h = h == iteratingNode ? h.Next : iteratingNode;
|
||||
}
|
||||
|
||||
iteratingNode = null;
|
||||
@@ -97,9 +86,8 @@ namespace Cysharp.Threading.Tasks
|
||||
LogError(ex);
|
||||
}
|
||||
|
||||
preserveRemoveSelf = false;
|
||||
var next = h == iteratingNode ? h.Next : iteratingNode;
|
||||
iteratingNode = null;
|
||||
var next = h.Next;
|
||||
Remove(h);
|
||||
h = next;
|
||||
}
|
||||
@@ -132,9 +120,8 @@ namespace Cysharp.Threading.Tasks
|
||||
LogError(ex);
|
||||
}
|
||||
|
||||
preserveRemoveSelf = false;
|
||||
var next = h == iteratingNode ? h.Next : iteratingNode;
|
||||
iteratingNode = null;
|
||||
var next = h.Next;
|
||||
Remove(h);
|
||||
h = next;
|
||||
}
|
||||
@@ -167,9 +154,8 @@ namespace Cysharp.Threading.Tasks
|
||||
LogError(ex);
|
||||
}
|
||||
|
||||
preserveRemoveSelf = false;
|
||||
var next = h == iteratingNode ? h.Next : iteratingNode;
|
||||
iteratingNode = null;
|
||||
var next = h.Next;
|
||||
Remove(h);
|
||||
h = next;
|
||||
}
|
||||
@@ -241,71 +227,65 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
if (iteratingNode != null && iteratingNode == handler)
|
||||
var prev = handler.Prev;
|
||||
var next = handler.Next;
|
||||
|
||||
if (next != null)
|
||||
{
|
||||
// if remove self, reserve remove self after invoke completed.
|
||||
preserveRemoveSelf = true;
|
||||
next.Prev = prev;
|
||||
}
|
||||
else
|
||||
|
||||
if (handler == head)
|
||||
{
|
||||
var prev = handler.Prev;
|
||||
var next = handler.Next;
|
||||
|
||||
if (next != null)
|
||||
{
|
||||
next.Prev = prev;
|
||||
}
|
||||
|
||||
if (handler == head)
|
||||
{
|
||||
head = next;
|
||||
}
|
||||
else if (handler == iteratingHead)
|
||||
{
|
||||
iteratingHead = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// when handler is head, prev indicate last so don't use it.
|
||||
if (prev != null)
|
||||
{
|
||||
prev.Next = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (head != null)
|
||||
{
|
||||
if (head.Prev == handler)
|
||||
{
|
||||
if (prev != head)
|
||||
{
|
||||
head.Prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
head.Prev = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iteratingHead != null)
|
||||
{
|
||||
if (iteratingHead.Prev == handler)
|
||||
{
|
||||
if (prev != iteratingHead.Prev)
|
||||
{
|
||||
iteratingHead.Prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
iteratingHead.Prev = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler.Prev = null;
|
||||
handler.Next = null;
|
||||
head = next;
|
||||
}
|
||||
// when handler is head, prev indicate last so don't use it.
|
||||
else if (prev != null)
|
||||
{
|
||||
prev.Next = next;
|
||||
}
|
||||
|
||||
if (handler == iteratingNode)
|
||||
{
|
||||
iteratingNode = next;
|
||||
}
|
||||
if (handler == iteratingHead)
|
||||
{
|
||||
iteratingHead = next;
|
||||
}
|
||||
|
||||
if (head != null)
|
||||
{
|
||||
if (head.Prev == handler)
|
||||
{
|
||||
if (prev != head)
|
||||
{
|
||||
head.Prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
head.Prev = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iteratingHead != null)
|
||||
{
|
||||
if (iteratingHead.Prev == handler)
|
||||
{
|
||||
if (prev != iteratingHead.Prev)
|
||||
{
|
||||
iteratingHead.Prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
iteratingHead.Prev = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler.Prev = null;
|
||||
handler.Next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,13 +32,11 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
if (cancellationTokenSource == null)
|
||||
{
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
if (!awakeCalled)
|
||||
{
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||
}
|
||||
}
|
||||
|
||||
if (!awakeCalled)
|
||||
{
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||
}
|
||||
|
||||
return cancellationTokenSource.Token;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +81,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (trigger.called) return false;
|
||||
if (trigger.called || trigger.awakeCalled) return false;
|
||||
if (trigger == null)
|
||||
{
|
||||
trigger.OnDestroy();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#pragma warning disable 0649
|
||||
|
||||
#if UNITASK_NETCORE || UNITY_2022_3_OR_NEWER
|
||||
#define SUPPORT_VALUETASK
|
||||
#endif
|
||||
|
||||
#if SUPPORT_VALUETASK
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks.Sources;
|
||||
@@ -10,7 +16,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static ValueTask AsValueTask(this in UniTask task)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
#if (UNITASK_NETCORE && NETSTANDARD2_0)
|
||||
return new ValueTask(new UniTaskValueTaskSource(task), 0);
|
||||
#else
|
||||
return task;
|
||||
@@ -19,7 +25,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
#if (UNITASK_NETCORE && NETSTANDARD2_0)
|
||||
return new ValueTask<T>(new UniTaskValueTaskSource<T>(task), 0);
|
||||
#else
|
||||
return task;
|
||||
@@ -36,7 +42,7 @@ namespace Cysharp.Threading.Tasks
|
||||
await task;
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
#if (UNITASK_NETCORE && NETSTANDARD2_0)
|
||||
|
||||
class UniTaskValueTaskSource : IValueTaskSource
|
||||
{
|
||||
@@ -95,3 +101,4 @@ namespace Cysharp.Threading.Tasks
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8760bbbab905a534eb6fb7b61b736926
|
||||
guid: d38f0478933be42d895c37b862540a1c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
@@ -32,14 +33,14 @@ namespace Cysharp.Threading.Tasks
|
||||
return new YieldAwaitable(timing);
|
||||
}
|
||||
|
||||
public static UniTask Yield(CancellationToken cancellationToken)
|
||||
public static UniTask Yield(CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
|
||||
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken)
|
||||
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token);
|
||||
return new UniTask(YieldPromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +48,7 @@ namespace Cysharp.Threading.Tasks
|
||||
/// </summary>
|
||||
public static UniTask NextFrame()
|
||||
{
|
||||
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, out var token), token);
|
||||
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, false, out var token), token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,87 +56,113 @@ namespace Cysharp.Threading.Tasks
|
||||
/// </summary>
|
||||
public static UniTask NextFrame(PlayerLoopTiming timing)
|
||||
{
|
||||
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, out var token), token);
|
||||
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, false, out var token), token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Similar as UniTask.Yield but guaranteed run on next frame.
|
||||
/// </summary>
|
||||
public static UniTask NextFrame(CancellationToken cancellationToken)
|
||||
public static UniTask NextFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
|
||||
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Similar as UniTask.Yield but guaranteed run on next frame.
|
||||
/// </summary>
|
||||
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken)
|
||||
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
|
||||
return new UniTask(NextFramePromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate).
|
||||
/// </summary>
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await Awaitable.EndOfFrameAsync(cancellationToken);
|
||||
}
|
||||
#else
|
||||
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
|
||||
public static YieldAwaitable WaitForEndOfFrame()
|
||||
{
|
||||
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken).
|
||||
/// </summary>
|
||||
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken)
|
||||
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
|
||||
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
|
||||
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
|
||||
{
|
||||
var source = WaitForEndOfFramePromise.Create(coroutineRunner, CancellationToken.None, false, out var token);
|
||||
return new UniTask(source, token);
|
||||
}
|
||||
|
||||
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
var source = WaitForEndOfFramePromise.Create(coroutineRunner, cancellationToken, cancelImmediately, out var token);
|
||||
return new UniTask(source, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate).
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate).
|
||||
/// </summary>
|
||||
public static YieldAwaitable WaitForFixedUpdate()
|
||||
{
|
||||
return UniTask.Yield(PlayerLoopTiming.FixedUpdate);
|
||||
// use LastFixedUpdate instead of FixedUpdate
|
||||
// https://github.com/Cysharp/UniTask/issues/377
|
||||
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken).
|
||||
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken).
|
||||
/// </summary>
|
||||
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken)
|
||||
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken, bool cancelImmediately = false)
|
||||
{
|
||||
return UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken);
|
||||
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask WaitForSeconds(float duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return Delay(Mathf.RoundToInt(1000 * duration), ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask WaitForSeconds(int duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return Delay(1000 * duration, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
if (delayFrameCount < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount);
|
||||
}
|
||||
|
||||
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, out var token), token);
|
||||
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
||||
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
|
||||
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
if (delayTimeSpan < TimeSpan.Zero)
|
||||
{
|
||||
@@ -154,16 +181,16 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
case DelayType.UnscaledDeltaTime:
|
||||
{
|
||||
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
case DelayType.Realtime:
|
||||
{
|
||||
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
case DelayType.DeltaTime:
|
||||
default:
|
||||
{
|
||||
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,13 +207,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
YieldPromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -198,8 +227,17 @@ namespace Cysharp.Threading.Tasks
|
||||
result = new YieldPromise();
|
||||
}
|
||||
|
||||
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (YieldPromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -217,7 +255,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +298,8 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -269,14 +316,16 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
int frameCount;
|
||||
CancellationToken cancellationToken;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
NextFramePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -290,6 +339,16 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (NextFramePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -307,7 +366,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,10 +414,138 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitForEndOfFramePromise : IUniTaskSource, ITaskPoolNode<WaitForEndOfFramePromise>, System.Collections.IEnumerator
|
||||
{
|
||||
static TaskPool<WaitForEndOfFramePromise> pool;
|
||||
WaitForEndOfFramePromise nextNode;
|
||||
public ref WaitForEndOfFramePromise NextNode => ref nextNode;
|
||||
|
||||
static WaitForEndOfFramePromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitForEndOfFramePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
WaitForEndOfFramePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitForEndOfFramePromise();
|
||||
}
|
||||
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitForEndOfFramePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
coroutineRunner.StartCoroutine(result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
Reset(); // Reset Enumerator
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
// Coroutine Runner implementation
|
||||
|
||||
static readonly WaitForEndOfFrame waitForEndOfFrameYieldInstruction = new WaitForEndOfFrame();
|
||||
bool isFirst = true;
|
||||
|
||||
object IEnumerator.Current => waitForEndOfFrameYieldInstruction;
|
||||
|
||||
bool IEnumerator.MoveNext()
|
||||
{
|
||||
if (isFirst)
|
||||
{
|
||||
isFirst = false;
|
||||
return true; // start WaitForEndOfFrame
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
isFirst = true;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
||||
{
|
||||
static TaskPool<DelayFramePromise> pool;
|
||||
@@ -366,6 +560,8 @@ namespace Cysharp.Threading.Tasks
|
||||
int initialFrame;
|
||||
int delayFrameCount;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
int currentFrameCount;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
@@ -374,7 +570,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -389,6 +585,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.delayFrameCount = delayFrameCount;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (DelayFramePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -406,7 +612,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,7 +657,19 @@ namespace Cysharp.Threading.Tasks
|
||||
// skip in initial frame.
|
||||
if (initialFrame == Time.frameCount)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// force use Realtime.
|
||||
if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
|
||||
{
|
||||
//goto ++currentFrameCount
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,6 +689,8 @@ namespace Cysharp.Threading.Tasks
|
||||
currentFrameCount = default;
|
||||
delayFrameCount = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -483,6 +710,8 @@ namespace Cysharp.Threading.Tasks
|
||||
float delayTimeSpan;
|
||||
float elapsed;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
@@ -490,7 +719,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -506,6 +735,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (DelayPromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -523,7 +762,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +821,8 @@ namespace Cysharp.Threading.Tasks
|
||||
delayTimeSpan = default;
|
||||
elapsed = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -594,6 +842,8 @@ namespace Cysharp.Threading.Tasks
|
||||
float elapsed;
|
||||
int initialFrame;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
@@ -601,7 +851,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -617,6 +867,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (DelayIgnoreTimeScalePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -634,7 +894,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,6 +953,8 @@ namespace Cysharp.Threading.Tasks
|
||||
delayFrameTimeSpan = default;
|
||||
elapsed = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -704,6 +973,8 @@ namespace Cysharp.Threading.Tasks
|
||||
long delayTimeSpanTicks;
|
||||
ValueStopwatch stopwatch;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
@@ -711,7 +982,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -726,6 +997,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.stopwatch = ValueStopwatch.StartNew();
|
||||
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (DelayRealtimePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -743,7 +1024,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,6 +1079,8 @@ namespace Cysharp.Threading.Tasks
|
||||
core.Reset();
|
||||
stopwatch = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,16 @@ namespace Cysharp.Threading.Tasks
|
||||
return factory();
|
||||
}
|
||||
|
||||
public static UniTask Create(Func<CancellationToken, UniTask> factory, CancellationToken cancellationToken)
|
||||
{
|
||||
return factory(cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask Create<T>(T state, Func<T, UniTask> factory)
|
||||
{
|
||||
return factory(state);
|
||||
}
|
||||
|
||||
public static UniTask<T> Create<T>(Func<UniTask<T>> factory)
|
||||
{
|
||||
return factory();
|
||||
@@ -137,11 +147,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return () => asyncAction(cancellationToken).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// helper of create add UniTaskVoid to delegate.
|
||||
/// </summary>
|
||||
public static Action Action<T>(T state, Func<T, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return () => asyncAction(state).Forget();
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For exampe: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction UnityAction(Func<UniTaskVoid> asyncAction)
|
||||
{
|
||||
@@ -150,13 +168,94 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For exampe: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction UnityAction(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||
{
|
||||
return () => asyncAction(cancellationToken).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(FooAsync, Argument))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction UnityAction<T>(T state, Func<T, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return () => asyncAction(state).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return (arg) => asyncAction(arg).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return (arg0, arg1) => asyncAction(arg0, arg1).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, UniTaskVoid> asyncAction)
|
||||
{
|
||||
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3).Forget();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg, CancellationToken cancellationToken) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||
{
|
||||
return (arg) => asyncAction(arg, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, CancellationToken cancellationToken) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||
{
|
||||
return (arg0, arg1) => asyncAction(arg0, arg1, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, CancellationToken cancellationToken) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||
{
|
||||
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async void(UniTaskVoid) UnityAction.
|
||||
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken) => { /* */ } ))
|
||||
/// </summary>
|
||||
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||
{
|
||||
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -175,6 +274,22 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask<T>(new DeferPromise<T>(factory), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defer the task creation just before call await.
|
||||
/// </summary>
|
||||
public static UniTask Defer<TState>(TState state, Func<TState, UniTask> factory)
|
||||
{
|
||||
return new UniTask(new DeferPromiseWithState<TState>(state, factory), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defer the task creation just before call await.
|
||||
/// </summary>
|
||||
public static UniTask<TResult> Defer<TState, TResult>(TState state, Func<TState, UniTask<TResult>> factory)
|
||||
{
|
||||
return new UniTask<TResult>(new DeferPromiseWithState<TState, TResult>(state, factory), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Never complete.
|
||||
/// </summary>
|
||||
@@ -194,6 +309,7 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ExceptionResultSource : IUniTaskSource
|
||||
{
|
||||
readonly ExceptionDispatchInfo exception;
|
||||
bool calledGet;
|
||||
|
||||
public ExceptionResultSource(Exception exception)
|
||||
{
|
||||
@@ -202,6 +318,11 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
if (!calledGet)
|
||||
{
|
||||
calledGet = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
exception.Throw();
|
||||
}
|
||||
|
||||
@@ -219,11 +340,20 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
continuation(state);
|
||||
}
|
||||
|
||||
~ExceptionResultSource()
|
||||
{
|
||||
if (!calledGet)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
|
||||
{
|
||||
readonly ExceptionDispatchInfo exception;
|
||||
bool calledGet;
|
||||
|
||||
public ExceptionResultSource(Exception exception)
|
||||
{
|
||||
@@ -232,12 +362,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
if (!calledGet)
|
||||
{
|
||||
calledGet = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
exception.Throw();
|
||||
return default;
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
if (!calledGet)
|
||||
{
|
||||
calledGet = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
exception.Throw();
|
||||
}
|
||||
|
||||
@@ -255,6 +395,14 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
continuation(state);
|
||||
}
|
||||
|
||||
~ExceptionResultSource()
|
||||
{
|
||||
if (!calledGet)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CanceledResultSource : IUniTaskSource
|
||||
@@ -405,6 +553,93 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DeferPromiseWithState<TState> : IUniTaskSource
|
||||
{
|
||||
Func<TState, UniTask> factory;
|
||||
TState argument;
|
||||
UniTask task;
|
||||
UniTask.Awaiter awaiter;
|
||||
|
||||
public DeferPromiseWithState(TState argument, Func<TState, UniTask> factory)
|
||||
{
|
||||
this.argument = argument;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
awaiter.GetResult();
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
var f = Interlocked.Exchange(ref factory, null);
|
||||
if (f != null)
|
||||
{
|
||||
task = f(argument);
|
||||
awaiter = task.GetAwaiter();
|
||||
}
|
||||
|
||||
return task.Status;
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
awaiter.SourceOnCompleted(continuation, state);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return task.Status;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DeferPromiseWithState<TState, TResult> : IUniTaskSource<TResult>
|
||||
{
|
||||
Func<TState, UniTask<TResult>> factory;
|
||||
TState argument;
|
||||
UniTask<TResult> task;
|
||||
UniTask<TResult>.Awaiter awaiter;
|
||||
|
||||
public DeferPromiseWithState(TState argument, Func<TState, UniTask<TResult>> factory)
|
||||
{
|
||||
this.argument = argument;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public TResult GetResult(short token)
|
||||
{
|
||||
return awaiter.GetResult();
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
awaiter.GetResult();
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
var f = Interlocked.Exchange(ref factory, null);
|
||||
if (f != null)
|
||||
{
|
||||
task = f(argument);
|
||||
awaiter = task.GetAwaiter();
|
||||
}
|
||||
|
||||
return task.Status;
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
awaiter.SourceOnCompleted(continuation, state);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return task.Status;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class NeverPromise<T> : IUniTaskSource<T>
|
||||
{
|
||||
static readonly Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
@@ -9,237 +9,56 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
#region OBSOLETE_RUN
|
||||
|
||||
// Run is a confusing name, use only RunOnThreadPool in the future.
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return RunOnThreadPool(action, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return RunOnThreadPool(action, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func();
|
||||
}
|
||||
return RunOnThreadPool(func, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await func();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
return RunOnThreadPool(func, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func(state);
|
||||
}
|
||||
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
|
||||
public static UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await func(state);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
@@ -9,30 +10,40 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public partial struct UniTask
|
||||
{
|
||||
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, out var token), token);
|
||||
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask WaitUntil<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, out var token), token);
|
||||
return new UniTask(WaitUntilPromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update)
|
||||
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, out var token), token);
|
||||
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask WaitWhile<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
return new UniTask(WaitWhilePromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
|
||||
{
|
||||
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
where T : class
|
||||
{
|
||||
var unityObject = target as UnityEngine.Object;
|
||||
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
|
||||
|
||||
return new UniTask<U>(isUnityObject
|
||||
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token)
|
||||
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
|
||||
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out var token)
|
||||
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out token), token);
|
||||
}
|
||||
|
||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
||||
@@ -48,6 +59,8 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
Func<bool> predicate;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
@@ -55,7 +68,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -69,6 +82,16 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
result.predicate = predicate;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitUntilPromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -86,7 +109,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,31 +166,36 @@ namespace Cysharp.Threading.Tasks
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||
sealed class WaitUntilPromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise<T>>
|
||||
{
|
||||
static TaskPool<WaitWhilePromise> pool;
|
||||
WaitWhilePromise nextNode;
|
||||
public ref WaitWhilePromise NextNode => ref nextNode;
|
||||
static TaskPool<WaitUntilPromise<T>> pool;
|
||||
WaitUntilPromise<T> nextNode;
|
||||
public ref WaitUntilPromise<T> NextNode => ref nextNode;
|
||||
|
||||
static WaitWhilePromise()
|
||||
static WaitUntilPromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
Func<bool> predicate;
|
||||
Func<T, bool> predicate;
|
||||
T argument;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
WaitWhilePromise()
|
||||
WaitUntilPromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -169,11 +204,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitWhilePromise();
|
||||
result = new WaitUntilPromise<T>();
|
||||
}
|
||||
|
||||
result.predicate = predicate;
|
||||
result.argument = argument;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitUntilPromise<T>)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -191,7 +237,141 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!predicate(argument))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
argument = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||
{
|
||||
static TaskPool<WaitWhilePromise> pool;
|
||||
WaitWhilePromise nextNode;
|
||||
public ref WaitWhilePromise NextNode => ref nextNode;
|
||||
|
||||
static WaitWhilePromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
Func<bool> predicate;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
WaitWhilePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitWhilePromise();
|
||||
}
|
||||
|
||||
result.predicate = predicate;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitWhilePromise)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,30 +421,36 @@ namespace Cysharp.Threading.Tasks
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||
sealed class WaitWhilePromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise<T>>
|
||||
{
|
||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||
WaitUntilCanceledPromise nextNode;
|
||||
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
|
||||
static TaskPool<WaitWhilePromise<T>> pool;
|
||||
WaitWhilePromise<T> nextNode;
|
||||
public ref WaitWhilePromise<T> NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilCanceledPromise()
|
||||
static WaitWhilePromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
Func<T, bool> predicate;
|
||||
T argument;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
WaitUntilCanceledPromise()
|
||||
WaitWhilePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, out short token)
|
||||
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -273,10 +459,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilCanceledPromise();
|
||||
result = new WaitWhilePromise<T>();
|
||||
}
|
||||
|
||||
result.predicate = predicate;
|
||||
result.argument = argument;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitWhilePromise<T>)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -294,7 +492,139 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (predicate(argument))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
argument = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||
{
|
||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||
WaitUntilCanceledPromise nextNode;
|
||||
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilCanceledPromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
WaitUntilCanceledPromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilCanceledPromise();
|
||||
}
|
||||
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitUntilCanceledPromise)state;
|
||||
promise.core.TrySetResult(null);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,6 +659,8 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -351,6 +683,8 @@ namespace Cysharp.Threading.Tasks
|
||||
Func<T, U> monitorFunction;
|
||||
IEqualityComparer<U> equalityComparer;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<U> core;
|
||||
|
||||
@@ -358,7 +692,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -376,6 +710,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.currentValue = monitorFunction(target);
|
||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitUntilValueChangedUnityObjectPromise<T, U>)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -393,7 +737,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,6 +804,8 @@ namespace Cysharp.Threading.Tasks
|
||||
monitorFunction = default;
|
||||
equalityComparer = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
@@ -474,6 +827,8 @@ namespace Cysharp.Threading.Tasks
|
||||
Func<T, U> monitorFunction;
|
||||
IEqualityComparer<U> equalityComparer;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
|
||||
UniTaskCompletionSourceCore<U> core;
|
||||
|
||||
@@ -481,7 +836,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -498,6 +853,16 @@ namespace Cysharp.Threading.Tasks
|
||||
result.currentValue = monitorFunction(target);
|
||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (WaitUntilValueChangedStandardObjectPromise<T, U>)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -515,7 +880,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +947,8 @@ namespace Cysharp.Threading.Tasks
|
||||
monitorFunction = default;
|
||||
equalityComparer = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
183
src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
183
src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public partial struct UniTask
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(IEnumerable<UniTask<T>> tasks)
|
||||
{
|
||||
return new WhenEachEnumerable<T>(tasks);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(params UniTask<T>[] tasks)
|
||||
{
|
||||
return new WhenEachEnumerable<T>(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct WhenEachResult<T>
|
||||
{
|
||||
public T Result { get; }
|
||||
public Exception Exception { get; }
|
||||
|
||||
//[MemberNotNullWhen(false, nameof(Exception))]
|
||||
public bool IsCompletedSuccessfully => Exception == null;
|
||||
|
||||
//[MemberNotNullWhen(true, nameof(Exception))]
|
||||
public bool IsFaulted => Exception != null;
|
||||
|
||||
public WhenEachResult(T result)
|
||||
{
|
||||
this.Result = result;
|
||||
this.Exception = null;
|
||||
}
|
||||
|
||||
public WhenEachResult(Exception exception)
|
||||
{
|
||||
if (exception == null) throw new ArgumentNullException(nameof(exception));
|
||||
this.Result = default;
|
||||
this.Exception = exception;
|
||||
}
|
||||
|
||||
public void TryThrow()
|
||||
{
|
||||
if (IsFaulted)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(Exception).Throw();
|
||||
}
|
||||
}
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
if (IsFaulted)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(Exception).Throw();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IsCompletedSuccessfully)
|
||||
{
|
||||
return Result?.ToString() ?? "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"Exception{{{Exception.Message}}}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum WhenEachState : byte
|
||||
{
|
||||
NotRunning,
|
||||
Running,
|
||||
Completed
|
||||
}
|
||||
|
||||
internal sealed class WhenEachEnumerable<T> : IUniTaskAsyncEnumerable<WhenEachResult<T>>
|
||||
{
|
||||
IEnumerable<UniTask<T>> source;
|
||||
|
||||
public WhenEachEnumerable(IEnumerable<UniTask<T>> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<WhenEachResult<T>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : IUniTaskAsyncEnumerator<WhenEachResult<T>>
|
||||
{
|
||||
readonly IEnumerable<UniTask<T>> source;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
Channel<WhenEachResult<T>> channel;
|
||||
IUniTaskAsyncEnumerator<WhenEachResult<T>> channelEnumerator;
|
||||
int completeCount;
|
||||
WhenEachState state;
|
||||
|
||||
public Enumerator(IEnumerable<UniTask<T>> source, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public WhenEachResult<T> Current => channelEnumerator.Current;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (state == WhenEachState.NotRunning)
|
||||
{
|
||||
state = WhenEachState.Running;
|
||||
channel = Channel.CreateSingleConsumerUnbounded<WhenEachResult<T>>();
|
||||
channelEnumerator = channel.Reader.ReadAllAsync().GetAsyncEnumerator(cancellationToken);
|
||||
|
||||
if (source is UniTask<T>[] array)
|
||||
{
|
||||
ConsumeAll(this, array, array.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var rentArray = ArrayPoolUtil.Materialize(source))
|
||||
{
|
||||
ConsumeAll(this, rentArray.Array, rentArray.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return channelEnumerator.MoveNextAsync();
|
||||
}
|
||||
|
||||
static void ConsumeAll(Enumerator self, UniTask<T>[] array, int length)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
RunWhenEachTask(self, array[i], length).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
static async UniTaskVoid RunWhenEachTask(Enumerator self, UniTask<T> task, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await task;
|
||||
self.channel.Writer.TryWrite(new WhenEachResult<T>(result));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.channel.Writer.TryWrite(new WhenEachResult<T>(ex));
|
||||
}
|
||||
|
||||
if (Interlocked.Increment(ref self.completeCount) == length)
|
||||
{
|
||||
self.state = WhenEachState.Completed;
|
||||
self.channel.Writer.TryComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (channelEnumerator != null)
|
||||
{
|
||||
await channelEnumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
if (state != WhenEachState.Completed)
|
||||
{
|
||||
state = WhenEachState.Completed;
|
||||
channel.Writer.TryComplete(new OperationCanceledException());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12bdad0556e999f4aa82da29415d361f
|
||||
guid: 7cac24fdda5112047a1cd3dd66b542c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS0436
|
||||
|
||||
#if UNITASK_NETCORE || UNITY_2022_3_OR_NEWER
|
||||
#define SUPPORT_VALUETASK
|
||||
#endif
|
||||
|
||||
using Cysharp.Threading.Tasks.CompilerServices;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
@@ -69,7 +73,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask<bool>(new IsCanceledSource(source), token);
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
#if SUPPORT_VALUETASK
|
||||
|
||||
public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
|
||||
{
|
||||
@@ -78,7 +82,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return default;
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
#if (UNITASK_NETCORE && NETSTANDARD2_0)
|
||||
return self.AsValueTask();
|
||||
#else
|
||||
return new System.Threading.Tasks.ValueTask(self.source, self.token);
|
||||
@@ -118,7 +122,7 @@ namespace Cysharp.Threading.Tasks
|
||||
this.source.GetResult(this.token);
|
||||
return CompletedTasks.AsyncUnit;
|
||||
}
|
||||
else if(this.source is IUniTaskSource<AsyncUnit> asyncUnitSource)
|
||||
else if (this.source is IUniTaskSource<AsyncUnit> asyncUnitSource)
|
||||
{
|
||||
return new UniTask<AsyncUnit>(asyncUnitSource, this.token);
|
||||
}
|
||||
@@ -440,7 +444,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return self.AsUniTask();
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
#if SUPPORT_VALUETASK
|
||||
|
||||
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
|
||||
{
|
||||
@@ -449,7 +453,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return new System.Threading.Tasks.ValueTask<T>(self.result);
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
#if (UNITASK_NETCORE && NETSTANDARD2_0)
|
||||
return self.AsValueTask();
|
||||
#else
|
||||
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
|
||||
|
||||
@@ -137,8 +137,8 @@ namespace Cysharp.Threading.Tasks
|
||||
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
|
||||
{
|
||||
continuation(continuationState);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -165,8 +165,8 @@ namespace Cysharp.Threading.Tasks
|
||||
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
|
||||
{
|
||||
continuation(continuationState);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -184,8 +184,8 @@ namespace Cysharp.Threading.Tasks
|
||||
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
|
||||
{
|
||||
continuation(continuationState);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -328,6 +328,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
short version;
|
||||
|
||||
AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
@@ -340,6 +341,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
result = new AutoResetUniTaskCompletionSource();
|
||||
}
|
||||
result.version = result.core.Version;
|
||||
TaskTracker.TrackActiveTask(result, 2);
|
||||
return result;
|
||||
}
|
||||
@@ -383,19 +385,19 @@ namespace Cysharp.Threading.Tasks
|
||||
[DebuggerHidden]
|
||||
public bool TrySetResult()
|
||||
{
|
||||
return core.TrySetResult(AsyncUnit.Default);
|
||||
return version == core.Version && core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return core.TrySetCanceled(cancellationToken);
|
||||
return version == core.Version && core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public bool TrySetException(Exception exception)
|
||||
{
|
||||
return core.TrySetException(exception);
|
||||
return version == core.Version && core.TrySetException(exception);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
@@ -409,7 +411,6 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
@@ -451,6 +452,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
short version;
|
||||
|
||||
AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
@@ -463,6 +465,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
result = new AutoResetUniTaskCompletionSource<T>();
|
||||
}
|
||||
result.version = result.core.Version;
|
||||
TaskTracker.TrackActiveTask(result, 2);
|
||||
return result;
|
||||
}
|
||||
@@ -506,19 +509,19 @@ namespace Cysharp.Threading.Tasks
|
||||
[DebuggerHidden]
|
||||
public bool TrySetResult(T result)
|
||||
{
|
||||
return core.TrySetResult(result);
|
||||
return version == core.Version && core.TrySetResult(result);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return core.TrySetCanceled(cancellationToken);
|
||||
return version == core.Version && core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public bool TrySetException(Exception exception)
|
||||
{
|
||||
return core.TrySetException(exception);
|
||||
return version == core.Version && core.TrySetException(exception);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
@@ -937,5 +940,5 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Cysharp.Threading.Tasks
|
||||
p.TrySetCanceled();
|
||||
break;
|
||||
case TaskStatus.Faulted:
|
||||
p.TrySetException(x.Exception);
|
||||
p.TrySetException(x.Exception.InnerException ?? x.Exception);
|
||||
break;
|
||||
case TaskStatus.RanToCompletion:
|
||||
p.TrySetResult(x.Result);
|
||||
@@ -58,7 +58,7 @@ namespace Cysharp.Threading.Tasks
|
||||
p.TrySetCanceled();
|
||||
break;
|
||||
case TaskStatus.Faulted:
|
||||
p.TrySetException(x.Exception);
|
||||
p.TrySetException(x.Exception.InnerException ?? x.Exception);
|
||||
break;
|
||||
case TaskStatus.RanToCompletion:
|
||||
p.TrySetResult();
|
||||
@@ -201,6 +201,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
task.Forget();
|
||||
return UniTask.FromCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
@@ -224,6 +225,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
task.Forget();
|
||||
return UniTask.FromCanceled<T>(cancellationToken);
|
||||
}
|
||||
|
||||
@@ -454,7 +456,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
|
||||
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCanceled).
|
||||
/// </summary>
|
||||
public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
{
|
||||
|
||||
@@ -74,16 +74,19 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
static async UniTaskVoid Fire<T>(AsyncSubject<T> subject, UniTask<T> task)
|
||||
{
|
||||
T value;
|
||||
try
|
||||
{
|
||||
var value = await task;
|
||||
subject.OnNext(value);
|
||||
subject.OnCompleted();
|
||||
value = await task;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
subject.OnError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
subject.OnNext(value);
|
||||
subject.OnCompleted();
|
||||
}
|
||||
|
||||
static async UniTaskVoid Fire(AsyncSubject<AsyncUnit> subject, UniTask task)
|
||||
@@ -91,13 +94,15 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
await task;
|
||||
subject.OnNext(AsyncUnit.Default);
|
||||
subject.OnCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
subject.OnError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
subject.OnNext(AsyncUnit.Default);
|
||||
subject.OnCompleted();
|
||||
}
|
||||
|
||||
class ToUniTaskObserver<T> : IObserver<T>
|
||||
@@ -128,7 +133,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
var self = (ToUniTaskObserver<T>)state;
|
||||
self.disposable.Dispose();
|
||||
self.promise.TrySetCanceled();
|
||||
self.promise.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
@@ -198,7 +203,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
var self = (FirstValueToUniTaskObserver<T>)state;
|
||||
self.disposable.Dispose();
|
||||
self.promise.TrySetCanceled();
|
||||
self.promise.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
|
||||
@@ -21,15 +21,20 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
return AwaitForAllAssets(asyncOperation, cancellationToken: cancellationToken);
|
||||
return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return AwaitForAllAssets(asyncOperation, progress: null, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
|
||||
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
|
||||
@@ -95,15 +100,20 @@ namespace Cysharp.Threading.Tasks
|
||||
AssetBundleRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AssetBundleRequestAllAssetsConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -118,6 +128,19 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AssetBundleRequestAllAssetsConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -135,7 +158,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +191,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -188,8 +224,28 @@ namespace Cysharp.Threading.Tasks
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.allAssets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,17 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
|
||||
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
|
||||
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
|
||||
@@ -39,15 +44,15 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
AsyncGPUReadbackRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
|
||||
|
||||
AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -61,6 +66,16 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var promise = (AsyncGPUReadbackRequestAwaiterConfiguredSource)state;
|
||||
promise.core.TrySetCanceled(promise.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -78,7 +93,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +153,8 @@ namespace Cysharp.Threading.Tasks
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
// AsyncInstantiateOperation was added since Unity 2022.3.20 / 2023.3.0b7
|
||||
#if UNITY_2022_3 && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17 || UNITY_2022_3_18 || UNITY_2022_3_19)
|
||||
#define UNITY_2022_SUPPORT
|
||||
#endif
|
||||
|
||||
#if UNITY_2022_SUPPORT || UNITY_2023_3_OR_NEWER
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class AsyncInstantiateOperationExtensions
|
||||
{
|
||||
// AsyncInstantiateOperation<T> has GetAwaiter so no need to impl
|
||||
// public static UniTask<T[]>.Awaiter GetAwaiter<T>(this AsyncInstantiateOperation<T> operation) where T : Object
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> ToUniTask(this AsyncInstantiateOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
|
||||
return new UniTask<UnityEngine.Object[]>(AsyncInstantiateOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken)
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<T[]> ToUniTask<T>(this AsyncInstantiateOperation<T> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T[]>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
|
||||
return new UniTask<T[]>(AsyncInstantiateOperationConfiguredSource<T>.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
sealed class AsyncInstantiateOperationConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncInstantiateOperationConfiguredSource> pool;
|
||||
AsyncInstantiateOperationConfiguredSource nextNode;
|
||||
public ref AsyncInstantiateOperationConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncInstantiateOperationConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncInstantiateOperation asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AsyncInstantiateOperationConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AsyncInstantiateOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncInstantiateOperationConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AsyncInstantiateOperationConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
{
|
||||
progress.Report(asyncOperation.progress);
|
||||
}
|
||||
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
core.TrySetResult(asyncOperation.Result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncInstantiateOperationConfiguredSource<T> : IUniTaskSource<T[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource<T>>
|
||||
where T : UnityEngine.Object
|
||||
{
|
||||
static TaskPool<AsyncInstantiateOperationConfiguredSource<T>> pool;
|
||||
AsyncInstantiateOperationConfiguredSource<T> nextNode;
|
||||
public ref AsyncInstantiateOperationConfiguredSource<T> NextNode => ref nextNode;
|
||||
|
||||
static AsyncInstantiateOperationConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncInstantiateOperation<T> asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<T[]> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AsyncInstantiateOperationConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T[]> Create(AsyncInstantiateOperation<T> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<T[]>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncInstantiateOperationConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AsyncInstantiateOperationConfiguredSource<T>)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
{
|
||||
progress.Report(asyncOperation.progress);
|
||||
}
|
||||
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
core.TrySetResult(asyncOperation.Result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3518da33b6245d341a0ef3670ee9268b
|
||||
timeCreated: 1488689723
|
||||
licenseType: Pro
|
||||
guid: 8321f4244edfdcd4798b4fcc92a736c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
@@ -15,23 +15,31 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
#region AsyncOperation
|
||||
|
||||
#if !UNITY_2023_1_OR_NEWER
|
||||
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
|
||||
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
return new AsyncOperationAwaiter(asyncOperation);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
|
||||
@@ -88,15 +96,20 @@ namespace Cysharp.Threading.Tasks
|
||||
AsyncOperation asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AsyncOperationConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -111,6 +124,19 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AsyncOperationConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -128,7 +154,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +183,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -174,11 +213,31 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -196,12 +255,17 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
|
||||
@@ -262,15 +326,20 @@ namespace Cysharp.Threading.Tasks
|
||||
ResourceRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
ResourceRequestConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -285,6 +354,19 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (ResourceRequestConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -302,7 +384,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +417,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -352,11 +447,31 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -375,12 +490,17 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
|
||||
@@ -441,15 +561,20 @@ namespace Cysharp.Threading.Tasks
|
||||
AssetBundleRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AssetBundleRequestConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -464,6 +589,19 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AssetBundleRequestConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -481,7 +619,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,6 +652,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -531,11 +682,31 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -555,12 +726,17 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
|
||||
@@ -621,15 +797,20 @@ namespace Cysharp.Threading.Tasks
|
||||
AssetBundleCreateRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AssetBundle> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
AssetBundleCreateRequestConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -644,6 +825,19 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (AssetBundleCreateRequestConfiguredSource)state;
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -661,7 +855,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,6 +888,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -711,11 +918,31 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.assetBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -735,7 +962,12 @@ namespace Cysharp.Threading.Tasks
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
|
||||
@@ -747,7 +979,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
|
||||
@@ -816,15 +1048,20 @@ namespace Cysharp.Threading.Tasks
|
||||
UnityWebRequestAsyncOperation asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityWebRequest> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
UnityWebRequestAsyncOperationConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -839,6 +1076,20 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (UnityWebRequestAsyncOperationConfiguredSource)state;
|
||||
source.asyncOperation.webRequest.Abort();
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -856,7 +1107,14 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,6 +1140,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
asyncOperation.webRequest.Abort();
|
||||
@@ -914,11 +1178,35 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.webRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
|
||||
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsAsyncOperationBase = x => x.typeName == "AsyncOperation";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsAssetBundleModule = x => x.typeName == "AssetBundleRequest" || x.typeName == "AssetBundleCreateRequest";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
|
||||
@@ -43,18 +44,30 @@ namespace Cysharp.Threading.Tasks
|
||||
<# } #>
|
||||
#region <#= t.typeName #>
|
||||
|
||||
<# if (IsAsyncOperationBase(t)) { #>
|
||||
#if !UNITY_2023_1_OR_NEWER
|
||||
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
|
||||
<# } #>
|
||||
public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
return new <#= t.typeName #>Awaiter(asyncOperation);
|
||||
}
|
||||
<# if (IsAsyncOperationBase(t)) { #>
|
||||
#endif
|
||||
<# } #>
|
||||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
|
||||
}
|
||||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
|
||||
@@ -70,7 +83,7 @@ namespace Cysharp.Threading.Tasks
|
||||
<# } else { #>
|
||||
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
|
||||
<# } #>
|
||||
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
|
||||
}
|
||||
|
||||
public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion
|
||||
@@ -151,15 +164,20 @@ namespace Cysharp.Threading.Tasks
|
||||
<#= t.typeName #> asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
bool cancelImmediately;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
|
||||
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
<#= t.typeName #>ConfiguredSource()
|
||||
{
|
||||
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -174,6 +192,22 @@ namespace Cysharp.Threading.Tasks
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.cancelImmediately = cancelImmediately;
|
||||
result.completed = false;
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||
{
|
||||
var source = (<#= t.typeName #>ConfiguredSource)state;
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
source.asyncOperation.webRequest.Abort();
|
||||
<# } #>
|
||||
source.core.TrySetCanceled(source.cancellationToken);
|
||||
}, result);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -195,7 +229,10 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +260,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Already completed
|
||||
if (completed || asyncOperation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
@@ -261,11 +304,42 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation.completed -= continuationAction;
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancelImmediately = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
else if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(asyncOperation.webRequest);
|
||||
}
|
||||
<# } else { #>
|
||||
else
|
||||
{
|
||||
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
|
||||
}
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
void InvokeCore(string item1, int item2, int item3)
|
||||
{
|
||||
innerEvent.Invoke(item1, item2, item3);
|
||||
Invoke((item1, item2, item3));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -673,7 +673,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
if (cancellationToken2.CanBeCanceled)
|
||||
{
|
||||
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
|
||||
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,13 +688,27 @@ namespace Cysharp.Threading.Tasks
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (UnityEventHandlerAsyncEnumerator)state;
|
||||
self.DisposeAsync().Forget();
|
||||
try
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.DisposeAsync().Forget();
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled2(object state)
|
||||
{
|
||||
var self = (UnityEventHandlerAsyncEnumerator)state;
|
||||
self.DisposeAsync().Forget();
|
||||
try
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.DisposeAsync().Forget();
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
@@ -706,6 +720,8 @@ namespace Cysharp.Threading.Tasks
|
||||
registration1.Dispose();
|
||||
registration2.Dispose();
|
||||
unityEvent.RemoveListener(unityAction);
|
||||
|
||||
completionSource.TrySetCanceled();
|
||||
}
|
||||
|
||||
return default;
|
||||
@@ -777,7 +793,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
if (cancellationToken2.CanBeCanceled)
|
||||
{
|
||||
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
|
||||
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,13 +809,27 @@ namespace Cysharp.Threading.Tasks
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (UnityEventHandlerAsyncEnumerator)state;
|
||||
self.DisposeAsync().Forget();
|
||||
try
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.DisposeAsync().Forget();
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled2(object state)
|
||||
{
|
||||
var self = (UnityEventHandlerAsyncEnumerator)state;
|
||||
self.DisposeAsync().Forget();
|
||||
try
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
self.DisposeAsync().Forget();
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
@@ -815,6 +845,8 @@ namespace Cysharp.Threading.Tasks
|
||||
disp.Dispose();
|
||||
}
|
||||
unityEvent.RemoveListener(unityAction);
|
||||
|
||||
completionSource.TrySetCanceled();
|
||||
}
|
||||
|
||||
return default;
|
||||
@@ -823,4 +855,4 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class UnityAwaitableExtensions
|
||||
{
|
||||
public static async UniTask AsUniTask(this UnityEngine.Awaitable awaitable)
|
||||
{
|
||||
await awaitable;
|
||||
}
|
||||
|
||||
public static async UniTask<T> AsUniTask<T>(this UnityEngine.Awaitable<T> awaitable)
|
||||
{
|
||||
return await awaitable;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c29533c9e4284dee914b71a6579ea274
|
||||
timeCreated: 1698895807
|
||||
@@ -12,17 +12,17 @@ namespace Cysharp.Threading.Tasks
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
|
||||
// <string> -> Text
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
@@ -68,22 +68,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
// <T> -> Text
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, bool rebindOnError = true)
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this AsyncReactiveProperty<T> source, Text text, bool rebindOnError = true)
|
||||
public static void BindTo<T>(this AsyncReactiveProperty<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -49,7 +49,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
if (Text != null)
|
||||
if(!string.IsNullOrWhiteSpace(Text))
|
||||
{
|
||||
msg = Error + Environment.NewLine + Text;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "2.2.4",
|
||||
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
||||
"version": "2.5.10",
|
||||
"unity": "2018.4",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||
"license": "MIT",
|
||||
"category": "Task",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 959c1472a5d812843bedf9341e87af3b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user