init
Some checks are pending
Sync Github To Image / sync-gitlink (push) Waiting to run
Sync Github To Image / sync-gitlab (push) Waiting to run
Sync Github To Image / sync-gitee (push) Waiting to run
Sync Github To Image / sync-atomgit (push) Waiting to run
Sync Github To Image / sync-gitcode (push) Waiting to run
Sync Github To Image / sync-framagit (push) Waiting to run

This commit is contained in:
陈思海 2025-01-09 11:14:16 +08:00
commit 0f01d0a681
367 changed files with 77320 additions and 0 deletions

51
.github/workflows/publish-release.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: Publish Release
on:
push:
tags:
- '*'
# branches: [main]
#schedule:
# 定时任务,每天 UTC 时间 0 点运行
#- cron: "0 0 * * *"
#workflow_dispatch:
permissions: # Global permissions configuration starts here
contents: read # 'read' access to repository contents
pull-requests: write # 'write' access to pull requests
jobs:
tags:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: "✏️ Generate release changelog"
uses: heinrichreimer/action-github-changelog-generator@v2.3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Commit CHANGELOG.md
run: |
git add CHANGELOG.md
git commit -m "[修改]1.修改更新日志"
- name: change-version-by-tag
uses: AlianBlank/github-action-tag-version@1.0.0
with:
version: ${{ github.ref_name }}
- name: Push changes
uses: ad-m/github-push-action@master
with:
branch: ${{ github.head_ref }}

288
.github/workflows/sync.yml vendored Normal file
View File

@ -0,0 +1,288 @@
name: Sync Github To Image
on:
push:
branches: [main]
#schedule:
# 定时任务,每天 UTC 时间 0 点运行
#- cron: "0 0 * * *"
#workflow_dispatch:
jobs:
sync-gitlink:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.GITLINK_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H code.gitlink.org.cn >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@code.gitlink.org.cn:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add gitlink "git@code.gitlink.org.cn:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune gitlink --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase gitlink ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u gitlink ${{ github.ref_name }} --tags --verbose
fi
sync-gitlab:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.GITLAB_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@gitlab.com:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add gitlab "git@gitlab.com:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune gitlab --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase gitlab ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u gitlab ${{ github.ref_name }} --tags --verbose
fi
sync-gitee:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.GITEE_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H gitee.com >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@gitee.com:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add gitee "git@gitee.com:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune gitee --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase gitee ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u gitee ${{ github.ref_name }} --tags --verbose
fi
sync-atomgit:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ATOMGIT_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H atomgit.com >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@atomgit.com:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add atomgit "git@atomgit.com:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune atomgit --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase atomgit ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u atomgit ${{ github.ref_name }} --tags --verbose
fi
sync-gitcode:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.GITCODE_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H gitcode.net >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@gitcode.net:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add gitcode "git@gitcode.net:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune gitcode --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase gitcode ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u gitcode ${{ github.ref_name }} --tags --verbose
fi
sync-framagit:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 为了 git pull --unshallow我们需要获取所有的提交历史
- name: Set up Git user
run: |
git config --global user.email "wangfj11@foxmail.com"
git config --global user.name "AlianBlank"
- name: Set SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.FRAMAGIT_ID_RSA }}" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa
# 信任域名
ssh-keyscan -H framagit.org >> ~/.ssh/known_hosts
# 查看当前分支
- name: Check current branch
run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }}
# 查看远端 地址
- name: echo git url
run: echo git@framagit.org:${{ github.Repository }}.git
# 添加远端
- name: add remote url
run: git remote add framagit "git@framagit.org:${{ github.Repository }}.git"
# 获取
- name: fetch
run: git fetch --prune framagit --tags --verbose
# 拉取
- name: pull and push
run: |
if [ "${{ github.ref_name }}" ]; then
git checkout ${{ github.ref_name }}
git pull --progress -v --no-rebase framagit ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支;
git push -u framagit ${{ github.ref_name }} --tags --verbose
fi

8
Editor.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 275b87293edc6634f9d72387851dbbdf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,62 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Cysharp.Threading.Tasks.Editor
{
// reflection call of UnityEditor.SplitterGUILayout
internal static class SplitterGUILayout
{
static BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
static Lazy<Type> splitterStateType = new Lazy<Type>(() =>
{
var type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterState");
return type;
});
static Lazy<ConstructorInfo> splitterStateCtor = new Lazy<ConstructorInfo>(() =>
{
var type = splitterStateType.Value;
return type.GetConstructor(flags, null, new Type[] { typeof(float[]), typeof(int[]), typeof(int[]) }, null);
});
static Lazy<Type> splitterGUILayoutType = new Lazy<Type>(() =>
{
var type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterGUILayout");
return type;
});
static Lazy<MethodInfo> beginVerticalSplit = new Lazy<MethodInfo>(() =>
{
var type = splitterGUILayoutType.Value;
return type.GetMethod("BeginVerticalSplit", flags, null, new Type[] { splitterStateType.Value, typeof(GUILayoutOption[]) }, null);
});
static Lazy<MethodInfo> endVerticalSplit = new Lazy<MethodInfo>(() =>
{
var type = splitterGUILayoutType.Value;
return type.GetMethod("EndVerticalSplit", flags, null, Type.EmptyTypes, null);
});
public static object CreateSplitterState(float[] relativeSizes, int[] minSizes, int[] maxSizes)
{
return splitterStateCtor.Value.Invoke(new object[] { relativeSizes, minSizes, maxSizes });
}
public static void BeginVerticalSplit(object splitterState, params GUILayoutOption[] options)
{
beginVerticalSplit.Value.Invoke(null, new object[] { splitterState, options });
}
public static void EndVerticalSplit()
{
endVerticalSplit.Value.Invoke(null, Type.EmptyTypes);
}
}
}

View File

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

View File

@ -0,0 +1,17 @@
{
"name": "UniTask.Editor",
"references": [
"UniTask.Runtime"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4129704b5a1a13841ba16f230bf24a57
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,182 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System;
using UnityEditor.IMGUI.Controls;
using Cysharp.Threading.Tasks.Internal;
using System.Text;
using System.Text.RegularExpressions;
namespace Cysharp.Threading.Tasks.Editor
{
public class UniTaskTrackerViewItem : TreeViewItem
{
static Regex removeHref = new Regex("<a href.+>(.+)</a>", RegexOptions.Compiled);
public string TaskType { get; set; }
public string Elapsed { get; set; }
public string Status { get; set; }
string position;
public string Position
{
get { return position; }
set
{
position = value;
PositionFirstLine = GetFirstLine(position);
}
}
public string PositionFirstLine { get; private set; }
static string GetFirstLine(string str)
{
var sb = new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
if (str[i] == '\r' || str[i] == '\n')
{
break;
}
sb.Append(str[i]);
}
return removeHref.Replace(sb.ToString(), "$1");
}
public UniTaskTrackerViewItem(int id) : base(id)
{
}
}
public class UniTaskTrackerTreeView : TreeView
{
const string sortedColumnIndexStateKey = "UniTaskTrackerTreeView_sortedColumnIndex";
public IReadOnlyList<TreeViewItem> CurrentBindingItems;
public UniTaskTrackerTreeView()
: this(new TreeViewState(), new MultiColumnHeader(new MultiColumnHeaderState(new[]
{
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("TaskType"), width = 20},
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Elapsed"), width = 10},
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Status"), width = 10},
new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Position")},
})))
{
}
UniTaskTrackerTreeView(TreeViewState state, MultiColumnHeader header)
: base(state, header)
{
rowHeight = 20;
showAlternatingRowBackgrounds = true;
showBorder = true;
header.sortingChanged += Header_sortingChanged;
header.ResizeToFit();
Reload();
header.sortedColumnIndex = SessionState.GetInt(sortedColumnIndexStateKey, 1);
}
public void ReloadAndSort()
{
var currentSelected = this.state.selectedIDs;
Reload();
Header_sortingChanged(this.multiColumnHeader);
this.state.selectedIDs = currentSelected;
}
private void Header_sortingChanged(MultiColumnHeader multiColumnHeader)
{
SessionState.SetInt(sortedColumnIndexStateKey, multiColumnHeader.sortedColumnIndex);
var index = multiColumnHeader.sortedColumnIndex;
var ascending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex);
var items = rootItem.children.Cast<UniTaskTrackerViewItem>();
IOrderedEnumerable<UniTaskTrackerViewItem> orderedEnumerable;
switch (index)
{
case 0:
orderedEnumerable = ascending ? items.OrderBy(item => item.TaskType) : items.OrderByDescending(item => item.TaskType);
break;
case 1:
orderedEnumerable = ascending ? items.OrderBy(item => double.Parse(item.Elapsed)) : items.OrderByDescending(item => double.Parse(item.Elapsed));
break;
case 2:
orderedEnumerable = ascending ? items.OrderBy(item => item.Status) : items.OrderByDescending(item => item.Elapsed);
break;
case 3:
orderedEnumerable = ascending ? items.OrderBy(item => item.Position) : items.OrderByDescending(item => item.PositionFirstLine);
break;
default:
throw new ArgumentOutOfRangeException(nameof(index), index, null);
}
CurrentBindingItems = rootItem.children = orderedEnumerable.Cast<TreeViewItem>().ToList();
BuildRows(rootItem);
}
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem { depth = -1 };
var children = new List<TreeViewItem>();
TaskTracker.ForEachActiveTask((trackingId, awaiterType, status, created, stackTrace) =>
{
children.Add(new UniTaskTrackerViewItem(trackingId) { TaskType = awaiterType, Status = status.ToString(), Elapsed = (DateTime.UtcNow - created).TotalSeconds.ToString("00.00"), Position = stackTrace });
});
CurrentBindingItems = children;
root.children = CurrentBindingItems as List<TreeViewItem>;
return root;
}
protected override bool CanMultiSelect(TreeViewItem item)
{
return false;
}
protected override void RowGUI(RowGUIArgs args)
{
var item = args.item as UniTaskTrackerViewItem;
for (var visibleColumnIndex = 0; visibleColumnIndex < args.GetNumVisibleColumns(); visibleColumnIndex++)
{
var rect = args.GetCellRect(visibleColumnIndex);
var columnIndex = args.GetColumn(visibleColumnIndex);
var labelStyle = args.selected ? EditorStyles.whiteLabel : EditorStyles.label;
labelStyle.alignment = TextAnchor.MiddleLeft;
switch (columnIndex)
{
case 0:
EditorGUI.LabelField(rect, item.TaskType, labelStyle);
break;
case 1:
EditorGUI.LabelField(rect, item.Elapsed, labelStyle);
break;
case 2:
EditorGUI.LabelField(rect, item.Status, labelStyle);
break;
case 3:
EditorGUI.LabelField(rect, item.PositionFirstLine, labelStyle);
break;
default:
throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, null);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,209 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System;
using UnityEditor.IMGUI.Controls;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks.Editor
{
public class UniTaskTrackerWindow : EditorWindow
{
static int interval;
static UniTaskTrackerWindow window;
[MenuItem("Window/UniTask Tracker")]
public static void OpenWindow()
{
if (window != null)
{
window.Close();
}
// will called OnEnable(singleton instance will be set).
GetWindow<UniTaskTrackerWindow>("UniTask Tracker").Show();
}
static readonly GUILayoutOption[] EmptyLayoutOption = new GUILayoutOption[0];
UniTaskTrackerTreeView treeView;
object splitterState;
void OnEnable()
{
window = this; // set singleton.
splitterState = SplitterGUILayout.CreateSplitterState(new float[] { 75f, 25f }, new int[] { 32, 32 }, null);
treeView = new UniTaskTrackerTreeView();
TaskTracker.EditorEnableState.EnableAutoReload = EditorPrefs.GetBool(TaskTracker.EnableAutoReloadKey, false);
TaskTracker.EditorEnableState.EnableTracking = EditorPrefs.GetBool(TaskTracker.EnableTrackingKey, false);
TaskTracker.EditorEnableState.EnableStackTrace = EditorPrefs.GetBool(TaskTracker.EnableStackTraceKey, false);
}
void OnGUI()
{
// Head
RenderHeadPanel();
// Splittable
SplitterGUILayout.BeginVerticalSplit(this.splitterState, EmptyLayoutOption);
{
// Column Tabble
RenderTable();
// StackTrace details
RenderDetailsPanel();
}
SplitterGUILayout.EndVerticalSplit();
}
#region HeadPanel
public static bool EnableAutoReload => TaskTracker.EditorEnableState.EnableAutoReload;
public static bool EnableTracking => TaskTracker.EditorEnableState.EnableTracking;
public static bool EnableStackTrace => TaskTracker.EditorEnableState.EnableStackTrace;
static readonly GUIContent EnableAutoReloadHeadContent = EditorGUIUtility.TrTextContent("Enable AutoReload", "Reload automatically.", (Texture)null);
static readonly GUIContent ReloadHeadContent = EditorGUIUtility.TrTextContent("Reload", "Reload View.", (Texture)null);
static readonly GUIContent GCHeadContent = EditorGUIUtility.TrTextContent("GC.Collect", "Invoke GC.Collect.", (Texture)null);
static readonly GUIContent EnableTrackingHeadContent = EditorGUIUtility.TrTextContent("Enable Tracking", "Start to track async/await UniTask. Performance impact: low", (Texture)null);
static readonly GUIContent EnableStackTraceHeadContent = EditorGUIUtility.TrTextContent("Enable StackTrace", "Capture StackTrace when task is started. Performance impact: high", (Texture)null);
// [Enable Tracking] | [Enable StackTrace]
void RenderHeadPanel()
{
EditorGUILayout.BeginVertical(EmptyLayoutOption);
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, EmptyLayoutOption);
if (GUILayout.Toggle(EnableAutoReload, EnableAutoReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableAutoReload)
{
TaskTracker.EditorEnableState.EnableAutoReload = !EnableAutoReload;
}
if (GUILayout.Toggle(EnableTracking, EnableTrackingHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableTracking)
{
TaskTracker.EditorEnableState.EnableTracking = !EnableTracking;
}
if (GUILayout.Toggle(EnableStackTrace, EnableStackTraceHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableStackTrace)
{
TaskTracker.EditorEnableState.EnableStackTrace = !EnableStackTrace;
}
GUILayout.FlexibleSpace();
if (GUILayout.Button(ReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption))
{
TaskTracker.CheckAndResetDirty();
treeView.ReloadAndSort();
Repaint();
}
if (GUILayout.Button(GCHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption))
{
GC.Collect(0);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
#endregion
#region TableColumn
Vector2 tableScroll;
GUIStyle tableListStyle;
void RenderTable()
{
if (tableListStyle == null)
{
tableListStyle = new GUIStyle("CN Box");
tableListStyle.margin.top = 0;
tableListStyle.padding.left = 3;
}
EditorGUILayout.BeginVertical(tableListStyle, EmptyLayoutOption);
this.tableScroll = EditorGUILayout.BeginScrollView(this.tableScroll, new GUILayoutOption[]
{
GUILayout.ExpandWidth(true),
GUILayout.MaxWidth(2000f)
});
var controlRect = EditorGUILayout.GetControlRect(new GUILayoutOption[]
{
GUILayout.ExpandHeight(true),
GUILayout.ExpandWidth(true)
});
treeView?.OnGUI(controlRect);
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
}
private void Update()
{
if (EnableAutoReload)
{
if (interval++ % 120 == 0)
{
if (TaskTracker.CheckAndResetDirty())
{
treeView.ReloadAndSort();
Repaint();
}
}
}
}
#endregion
#region Details
static GUIStyle detailsStyle;
Vector2 detailsScroll;
void RenderDetailsPanel()
{
if (detailsStyle == null)
{
detailsStyle = new GUIStyle("CN Message");
detailsStyle.wordWrap = false;
detailsStyle.stretchHeight = true;
detailsStyle.margin.right = 15;
}
string message = "";
var selected = treeView.state.selectedIDs;
if (selected.Count > 0)
{
var first = selected[0];
var item = treeView.CurrentBindingItems.FirstOrDefault(x => x.id == first) as UniTaskTrackerViewItem;
if (item != null)
{
message = item.Position;
}
}
detailsScroll = EditorGUILayout.BeginScrollView(this.detailsScroll, EmptyLayoutOption);
var vector = detailsStyle.CalcSize(new GUIContent(message));
EditorGUILayout.SelectableLabel(message, detailsStyle, new GUILayoutOption[]
{
GUILayout.ExpandHeight(true),
GUILayout.ExpandWidth(true),
GUILayout.MinWidth(vector.x),
GUILayout.MinHeight(vector.y)
});
EditorGUILayout.EndScrollView();
}
#endregion
}
}

View File

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

44
LICENSE.md Normal file
View File

@ -0,0 +1,44 @@
MIT License
Copyright (c) 2023 Blank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The MIT License (MIT)
Copyright (c) 2019 Yoshifumi Kawai / Cysharp, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
LICENSE.md.meta Normal file
View File

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

1156
README.md Normal file

File diff suppressed because it is too large Load Diff

7
README.md.meta Normal file
View File

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

1133
README_CN.md Normal file

File diff suppressed because it is too large Load Diff

7
README_CN.md.meta Normal file
View File

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

8
Runtime.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aa765154468d4b34eb34304100d39e64
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

245
Runtime/AsyncLazy.cs Normal file
View File

@ -0,0 +1,245 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public class AsyncLazy
{
static Action<object> continuation = SetCompletionSource;
Func<UniTask> taskFactory;
UniTaskCompletionSource completionSource;
UniTask.Awaiter awaiter;
object syncLock;
bool initialized;
public AsyncLazy(Func<UniTask> taskFactory)
{
this.taskFactory = taskFactory;
this.completionSource = new UniTaskCompletionSource();
this.syncLock = new object();
this.initialized = false;
}
internal AsyncLazy(UniTask task)
{
this.taskFactory = null;
this.completionSource = new UniTaskCompletionSource();
this.syncLock = null;
this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
}
public UniTask Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{
if (Volatile.Read(ref initialized))
{
return;
}
EnsureInitializedCore();
}
void EnsureInitializedCore()
{
lock (syncLock)
{
if (!Volatile.Read(ref initialized))
{
var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null)
{
var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true);
}
}
}
}
void SetCompletionSource(in UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
completionSource.TrySetResult();
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy)state;
try
{
self.awaiter.GetResult();
self.completionSource.TrySetResult();
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
}
}
public class AsyncLazy<T>
{
static Action<object> continuation = SetCompletionSource;
Func<UniTask<T>> taskFactory;
UniTaskCompletionSource<T> completionSource;
UniTask<T>.Awaiter awaiter;
object syncLock;
bool initialized;
public AsyncLazy(Func<UniTask<T>> taskFactory)
{
this.taskFactory = taskFactory;
this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = new object();
this.initialized = false;
}
internal AsyncLazy(UniTask<T> task)
{
this.taskFactory = null;
this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = null;
this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
}
public UniTask<T> Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{
if (Volatile.Read(ref initialized))
{
return;
}
EnsureInitializedCore();
}
void EnsureInitializedCore()
{
lock (syncLock)
{
if (!Volatile.Read(ref initialized))
{
var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null)
{
var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true);
}
}
}
}
void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
{
try
{
var result = awaiter.GetResult();
completionSource.TrySetResult(result);
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy<T>)state;
try
{
var result = self.awaiter.GetResult();
self.completionSource.TrySetResult(result);
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
}
}
}

11
Runtime/AsyncLazy.cs.meta Normal file
View File

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

View File

@ -0,0 +1,644 @@
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public interface IReadOnlyAsyncReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
{
T Value { get; }
IUniTaskAsyncEnumerable<T> WithoutCurrent();
UniTask<T> WaitAsync(CancellationToken cancellationToken = default);
}
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
{
new T Value { get; set; }
}
[Serializable]
public class AsyncReactiveProperty<T> : IAsyncReactiveProperty<T>, IDisposable
{
TriggerEvent<T> triggerEvent;
#if UNITY_2018_3_OR_NEWER
[UnityEngine.SerializeField]
#endif
T latestValue;
public T Value
{
get
{
return latestValue;
}
set
{
this.latestValue = value;
triggerEvent.SetResult(value);
}
}
public AsyncReactiveProperty(T value)
{
this.latestValue = value;
this.triggerEvent = default;
}
public IUniTaskAsyncEnumerable<T> WithoutCurrent()
{
return new WithoutCurrentEnumerable(this);
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
{
return new Enumerator(this, cancellationToken, true);
}
public void Dispose()
{
triggerEvent.SetCompleted();
}
public static implicit operator T(AsyncReactiveProperty<T> value)
{
return value.Value;
}
public override string ToString()
{
if (isValueType) return latestValue.ToString();
return latestValue?.ToString();
}
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
{
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
}
static bool isValueType;
static AsyncReactiveProperty()
{
isValueType = typeof(T).IsValueType;
}
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
{
static Action<object> cancellationCallback = CancellationCallback;
static TaskPool<WaitAsyncSource> pool;
WaitAsyncSource nextNode;
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
static WaitAsyncSource()
{
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
}
AsyncReactiveProperty<T> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<T> core;
WaitAsyncSource()
{
}
public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitAsyncSource();
}
result.parent = parent;
result.cancellationToken = cancellationToken;
if (cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
}
result.parent.triggerEvent.Add(result);
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
return result;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationTokenRegistration.Dispose();
cancellationTokenRegistration = default;
parent.triggerEvent.Remove(this);
parent = null;
cancellationToken = default;
return pool.TryPush(this);
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;
self.OnCanceled(self.cancellationToken);
}
// IUniTaskSource
public T GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
// ITriggerHandler
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public void OnCanceled(CancellationToken cancellationToken)
{
core.TrySetCanceled(cancellationToken);
}
public void OnCompleted()
{
// Complete as Cancel.
core.TrySetCanceled(CancellationToken.None);
}
public void OnError(Exception ex)
{
core.TrySetException(ex);
}
public void OnNext(T value)
{
core.TrySetResult(value);
}
}
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
{
readonly AsyncReactiveProperty<T> parent;
public WithoutCurrentEnumerable(AsyncReactiveProperty<T> parent)
{
this.parent = parent;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(parent, cancellationToken, false);
}
}
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
{
static Action<object> cancellationCallback = CancellationCallback;
readonly AsyncReactiveProperty<T> parent;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
T value;
bool isDisposed;
bool firstCall;
public Enumerator(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
{
this.parent = parent;
this.cancellationToken = cancellationToken;
this.firstCall = publishCurrentValue;
parent.triggerEvent.Add(this);
TaskTracker.TrackActiveTask(this, 3);
if (cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
}
}
public T Current => value;
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public UniTask<bool> MoveNextAsync()
{
// raise latest value on first call.
if (firstCall)
{
firstCall = false;
value = parent.Value;
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
public UniTask DisposeAsync()
{
if (!isDisposed)
{
isDisposed = true;
TaskTracker.RemoveTracking(this);
completionSource.TrySetCanceled(cancellationToken);
parent.triggerEvent.Remove(this);
}
return default;
}
public void OnNext(T value)
{
this.value = value;
completionSource.TrySetResult(true);
}
public void OnCanceled(CancellationToken cancellationToken)
{
DisposeAsync().Forget();
}
public void OnCompleted()
{
completionSource.TrySetResult(false);
}
public void OnError(Exception ex)
{
completionSource.TrySetException(ex);
}
static void CancellationCallback(object state)
{
var self = (Enumerator)state;
self.DisposeAsync().Forget();
}
}
}
public class ReadOnlyAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IDisposable
{
TriggerEvent<T> triggerEvent;
T latestValue;
IUniTaskAsyncEnumerator<T> enumerator;
public T Value
{
get
{
return latestValue;
}
}
public ReadOnlyAsyncReactiveProperty(T initialValue, IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
latestValue = initialValue;
ConsumeEnumerator(source, cancellationToken).Forget();
}
public ReadOnlyAsyncReactiveProperty(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
ConsumeEnumerator(source, cancellationToken).Forget();
}
async UniTaskVoid ConsumeEnumerator(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
enumerator = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await enumerator.MoveNextAsync())
{
var value = enumerator.Current;
this.latestValue = value;
triggerEvent.SetResult(value);
}
}
finally
{
await enumerator.DisposeAsync();
enumerator = null;
}
}
public IUniTaskAsyncEnumerable<T> WithoutCurrent()
{
return new WithoutCurrentEnumerable(this);
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
{
return new Enumerator(this, cancellationToken, true);
}
public void Dispose()
{
if (enumerator != null)
{
enumerator.DisposeAsync().Forget();
}
triggerEvent.SetCompleted();
}
public static implicit operator T(ReadOnlyAsyncReactiveProperty<T> value)
{
return value.Value;
}
public override string ToString()
{
if (isValueType) return latestValue.ToString();
return latestValue?.ToString();
}
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
{
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
}
static bool isValueType;
static ReadOnlyAsyncReactiveProperty()
{
isValueType = typeof(T).IsValueType;
}
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
{
static Action<object> cancellationCallback = CancellationCallback;
static TaskPool<WaitAsyncSource> pool;
WaitAsyncSource nextNode;
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
static WaitAsyncSource()
{
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
}
ReadOnlyAsyncReactiveProperty<T> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<T> core;
WaitAsyncSource()
{
}
public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitAsyncSource();
}
result.parent = parent;
result.cancellationToken = cancellationToken;
if (cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
}
result.parent.triggerEvent.Add(result);
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
return result;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationTokenRegistration.Dispose();
cancellationTokenRegistration = default;
parent.triggerEvent.Remove(this);
parent = null;
cancellationToken = default;
return pool.TryPush(this);
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;
self.OnCanceled(self.cancellationToken);
}
// IUniTaskSource
public T GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
TryReturn();
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
// ITriggerHandler
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public void OnCanceled(CancellationToken cancellationToken)
{
core.TrySetCanceled(cancellationToken);
}
public void OnCompleted()
{
// Complete as Cancel.
core.TrySetCanceled(CancellationToken.None);
}
public void OnError(Exception ex)
{
core.TrySetException(ex);
}
public void OnNext(T value)
{
core.TrySetResult(value);
}
}
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
{
readonly ReadOnlyAsyncReactiveProperty<T> parent;
public WithoutCurrentEnumerable(ReadOnlyAsyncReactiveProperty<T> parent)
{
this.parent = parent;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(parent, cancellationToken, false);
}
}
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
{
static Action<object> cancellationCallback = CancellationCallback;
readonly ReadOnlyAsyncReactiveProperty<T> parent;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
T value;
bool isDisposed;
bool firstCall;
public Enumerator(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
{
this.parent = parent;
this.cancellationToken = cancellationToken;
this.firstCall = publishCurrentValue;
parent.triggerEvent.Add(this);
TaskTracker.TrackActiveTask(this, 3);
if (cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
}
}
public T Current => value;
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
public UniTask<bool> MoveNextAsync()
{
// raise latest value on first call.
if (firstCall)
{
firstCall = false;
value = parent.Value;
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
public UniTask DisposeAsync()
{
if (!isDisposed)
{
isDisposed = true;
TaskTracker.RemoveTracking(this);
completionSource.TrySetCanceled(cancellationToken);
parent.triggerEvent.Remove(this);
}
return default;
}
public void OnNext(T value)
{
this.value = value;
completionSource.TrySetResult(true);
}
public void OnCanceled(CancellationToken cancellationToken)
{
DisposeAsync().Forget();
}
public void OnCompleted()
{
completionSource.TrySetResult(false);
}
public void OnError(Exception ex)
{
completionSource.TrySetException(ex);
}
static void CancellationCallback(object state)
{
var self = (Enumerator)state;
self.DisposeAsync().Forget();
}
}
}
public static class StateExtensions
{
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
return new ReadOnlyAsyncReactiveProperty<T>(source, cancellationToken);
}
public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, T initialValue, CancellationToken cancellationToken)
{
return new ReadOnlyAsyncReactiveProperty<T>(initialValue, source, cancellationToken);
}
}
}

View File

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

26
Runtime/AsyncUnit.cs Normal file
View File

@ -0,0 +1,26 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or
using System;
namespace Cysharp.Threading.Tasks
{
public readonly struct AsyncUnit : IEquatable<AsyncUnit>
{
public static readonly AsyncUnit Default = new AsyncUnit();
public override int GetHashCode()
{
return 0;
}
public bool Equals(AsyncUnit other)
{
return true;
}
public override string ToString()
{
return "()";
}
}
}

11
Runtime/AsyncUnit.cs.meta Normal file
View File

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

View File

@ -0,0 +1,23 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System.Collections.Generic;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public class CancellationTokenEqualityComparer : IEqualityComparer<CancellationToken>
{
public static readonly IEqualityComparer<CancellationToken> Default = new CancellationTokenEqualityComparer();
public bool Equals(CancellationToken x, CancellationToken y)
{
return x.Equals(y);
}
public int GetHashCode(CancellationToken obj)
{
return obj.GetHashCode();
}
}
}

View File

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

View File

@ -0,0 +1,182 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public static class CancellationTokenExtensions
{
static readonly Action<object> cancellationTokenCallback = Callback;
static readonly Action<object> disposeCallback = DisposeCallback;
public static CancellationToken ToCancellationToken(this UniTask task)
{
var cts = new CancellationTokenSource();
ToCancellationTokenCore(task, cts).Forget();
return cts.Token;
}
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
{
if (linkToken.IsCancellationRequested)
{
return linkToken;
}
if (!linkToken.CanBeCanceled)
{
return ToCancellationToken(task);
}
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
ToCancellationTokenCore(task, cts).Forget();
return cts.Token;
}
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
{
return ToCancellationToken(task.AsUniTask());
}
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
{
return ToCancellationToken(task.AsUniTask(), linkToken);
}
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
{
try
{
await task;
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
cts.Cancel();
cts.Dispose();
}
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return (UniTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration));
}
var promise = new UniTaskCompletionSource();
return (promise.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, promise));
}
static void Callback(object state)
{
var promise = (UniTaskCompletionSource)state;
promise.TrySetResult();
}
public static CancellationTokenAwaitable WaitUntilCanceled(this CancellationToken cancellationToken)
{
return new CancellationTokenAwaitable(cancellationToken);
}
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback)
{
var restoreFlow = false;
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}
try
{
return cancellationToken.Register(callback, false);
}
finally
{
if (restoreFlow)
{
ExecutionContext.RestoreFlow();
}
}
}
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action<object> callback, object state)
{
var restoreFlow = false;
if (!ExecutionContext.IsFlowSuppressed())
{
ExecutionContext.SuppressFlow();
restoreFlow = true;
}
try
{
return cancellationToken.Register(callback, state, false);
}
finally
{
if (restoreFlow)
{
ExecutionContext.RestoreFlow();
}
}
}
public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
{
return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
}
static void DisposeCallback(object state)
{
var d = (IDisposable)state;
d.Dispose();
}
}
public struct CancellationTokenAwaitable
{
CancellationToken cancellationToken;
public CancellationTokenAwaitable(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public Awaiter GetAwaiter()
{
return new Awaiter(cancellationToken);
}
public struct Awaiter : ICriticalNotifyCompletion
{
CancellationToken cancellationToken;
public Awaiter(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public bool IsCompleted => !cancellationToken.CanBeCanceled || cancellationToken.IsCancellationRequested;
public void GetResult()
{
}
public void OnCompleted(Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
cancellationToken.RegisterWithoutCaptureExecutionContext(continuation);
}
}
}
}

View File

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

View File

@ -0,0 +1,44 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System.Threading;
using UnityEngine;
using Cysharp.Threading.Tasks.Triggers;
using System;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks
{
public static partial class CancellationTokenSourceExtensions
{
readonly static Action<object> CancelCancellationTokenSourceStateDelegate = new Action<object>(CancelCancellationTokenSourceState);
static void CancelCancellationTokenSourceState(object state)
{
var cts = (CancellationTokenSource)state;
cts.Cancel();
}
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
{
return CancelAfterSlim(cts, TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming);
}
public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
{
return PlayerLoopTimer.StartNew(delayTimeSpan, false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts);
}
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Component component)
{
RegisterRaiseCancelOnDestroy(cts, component.gameObject);
}
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
{
var trigger = gameObject.GetAsyncDestroyTrigger();
trigger.CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts);
}
}
}

View File

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

450
Runtime/Channel.cs Normal file
View File

@ -0,0 +1,450 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public static class Channel
{
public static Channel<T> CreateSingleConsumerUnbounded<T>()
{
return new SingleConsumerUnboundedChannel<T>();
}
}
public abstract class Channel<TWrite, TRead>
{
public ChannelReader<TRead> Reader { get; protected set; }
public ChannelWriter<TWrite> Writer { get; protected set; }
public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel) => channel.Reader;
public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel) => channel.Writer;
}
public abstract class Channel<T> : Channel<T, T>
{
}
public abstract class ChannelReader<T>
{
public abstract bool TryRead(out T item);
public abstract UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken));
public abstract UniTask Completion { get; }
public virtual UniTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (this.TryRead(out var item))
{
return UniTask.FromResult(item);
}
return ReadAsyncCore(cancellationToken);
}
async UniTask<T> ReadAsyncCore(CancellationToken cancellationToken = default(CancellationToken))
{
if (await WaitToReadAsync(cancellationToken))
{
if (TryRead(out var item))
{
return item;
}
}
throw new ChannelClosedException();
}
public abstract IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken));
}
public abstract class ChannelWriter<T>
{
public abstract bool TryWrite(T item);
public abstract bool TryComplete(Exception error = null);
public void Complete(Exception error = null)
{
if (!TryComplete(error))
{
throw new ChannelClosedException();
}
}
}
public partial class ChannelClosedException : InvalidOperationException
{
public ChannelClosedException() :
base("Channel is already closed.")
{ }
public ChannelClosedException(string message) : base(message) { }
public ChannelClosedException(Exception innerException) :
base("Channel is already closed", innerException)
{ }
public ChannelClosedException(string message, Exception innerException) : base(message, innerException) { }
}
internal class SingleConsumerUnboundedChannel<T> : Channel<T>
{
readonly Queue<T> items;
readonly SingleConsumerUnboundedChannelReader readerSource;
UniTaskCompletionSource completedTaskSource;
UniTask completedTask;
Exception completionError;
bool closed;
public SingleConsumerUnboundedChannel()
{
items = new Queue<T>();
Writer = new SingleConsumerUnboundedChannelWriter(this);
readerSource = new SingleConsumerUnboundedChannelReader(this);
Reader = readerSource;
}
sealed class SingleConsumerUnboundedChannelWriter : ChannelWriter<T>
{
readonly SingleConsumerUnboundedChannel<T> parent;
public SingleConsumerUnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent)
{
this.parent = parent;
}
public override bool TryWrite(T item)
{
bool waiting;
lock (parent.items)
{
if (parent.closed) return false;
parent.items.Enqueue(item);
waiting = parent.readerSource.isWaiting;
}
if (waiting)
{
parent.readerSource.SingalContinuation();
}
return true;
}
public override bool TryComplete(Exception error = null)
{
bool waiting;
lock (parent.items)
{
if (parent.closed) return false;
parent.closed = true;
waiting = parent.readerSource.isWaiting;
if (parent.items.Count == 0)
{
if (error == null)
{
if (parent.completedTaskSource != null)
{
parent.completedTaskSource.TrySetResult();
}
else
{
parent.completedTask = UniTask.CompletedTask;
}
}
else
{
if (parent.completedTaskSource != null)
{
parent.completedTaskSource.TrySetException(error);
}
else
{
parent.completedTask = UniTask.FromException(error);
}
}
if (waiting)
{
parent.readerSource.SingalCompleted(error);
}
}
parent.completionError = error;
}
return true;
}
}
sealed class SingleConsumerUnboundedChannelReader : ChannelReader<T>, IUniTaskSource<bool>
{
readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
readonly SingleConsumerUnboundedChannel<T> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<bool> core;
internal bool isWaiting;
public SingleConsumerUnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
{
this.parent = parent;
TaskTracker.TrackActiveTask(this, 4);
}
public override UniTask Completion
{
get
{
if (parent.completedTaskSource != null) return parent.completedTaskSource.Task;
if (parent.closed)
{
return parent.completedTask;
}
parent.completedTaskSource = new UniTaskCompletionSource();
return parent.completedTaskSource.Task;
}
}
public override bool TryRead(out T item)
{
lock (parent.items)
{
if (parent.items.Count != 0)
{
item = parent.items.Dequeue();
// complete when all value was consumed.
if (parent.closed && parent.items.Count == 0)
{
if (parent.completionError != null)
{
if (parent.completedTaskSource != null)
{
parent.completedTaskSource.TrySetException(parent.completionError);
}
else
{
parent.completedTask = UniTask.FromException(parent.completionError);
}
}
else
{
if (parent.completedTaskSource != null)
{
parent.completedTaskSource.TrySetResult();
}
else
{
parent.completedTask = UniTask.CompletedTask;
}
}
}
}
else
{
item = default;
return false;
}
}
return true;
}
public override UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return UniTask.FromCanceled<bool>(cancellationToken);
}
lock (parent.items)
{
if (parent.items.Count != 0)
{
return CompletedTasks.True;
}
if (parent.closed)
{
if (parent.completionError == null)
{
return CompletedTasks.False;
}
else
{
return UniTask.FromException<bool>(parent.completionError);
}
}
cancellationTokenRegistration.Dispose();
core.Reset();
isWaiting = true;
this.cancellationToken = cancellationToken;
if (this.cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
}
return new UniTask<bool>(this, core.Version);
}
}
public void SingalContinuation()
{
core.TrySetResult(true);
}
public void SingalCancellation(CancellationToken cancellationToken)
{
TaskTracker.RemoveTracking(this);
core.TrySetCanceled(cancellationToken);
}
public void SingalCompleted(Exception error)
{
if (error != null)
{
TaskTracker.RemoveTracking(this);
core.TrySetException(error);
}
else
{
TaskTracker.RemoveTracking(this);
core.TrySetResult(false);
}
}
public override IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default)
{
return new ReadAllAsyncEnumerable(this, cancellationToken);
}
bool IUniTaskSource<bool>.GetResult(short token)
{
return core.GetResult(token);
}
void IUniTaskSource.GetResult(short token)
{
core.GetResult(token);
}
UniTaskStatus IUniTaskSource.GetStatus(short token)
{
return core.GetStatus(token);
}
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
static void CancellationCallback(object state)
{
var self = (SingleConsumerUnboundedChannelReader)state;
self.SingalCancellation(self.cancellationToken);
}
sealed class ReadAllAsyncEnumerable : IUniTaskAsyncEnumerable<T>, IUniTaskAsyncEnumerator<T>
{
readonly Action<object> CancellationCallback1Delegate = CancellationCallback1;
readonly Action<object> CancellationCallback2Delegate = CancellationCallback2;
readonly SingleConsumerUnboundedChannelReader parent;
CancellationToken cancellationToken1;
CancellationToken cancellationToken2;
CancellationTokenRegistration cancellationTokenRegistration1;
CancellationTokenRegistration cancellationTokenRegistration2;
T current;
bool cacheValue;
bool running;
public ReadAllAsyncEnumerable(SingleConsumerUnboundedChannelReader parent, CancellationToken cancellationToken)
{
this.parent = parent;
this.cancellationToken1 = cancellationToken;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
if (running)
{
throw new InvalidOperationException("Enumerator is already running, does not allow call GetAsyncEnumerator twice.");
}
if (this.cancellationToken1 != cancellationToken)
{
this.cancellationToken2 = cancellationToken;
}
if (this.cancellationToken1.CanBeCanceled)
{
this.cancellationTokenRegistration1 = this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
}
if (this.cancellationToken2.CanBeCanceled)
{
this.cancellationTokenRegistration2 = this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
}
running = true;
return this;
}
public T Current
{
get
{
if (cacheValue)
{
return current;
}
parent.TryRead(out current);
return current;
}
}
public UniTask<bool> MoveNextAsync()
{
cacheValue = false;
return parent.WaitToReadAsync(CancellationToken.None); // ok to use None, registered in ctor.
}
public UniTask DisposeAsync()
{
cancellationTokenRegistration1.Dispose();
cancellationTokenRegistration2.Dispose();
return default;
}
static void CancellationCallback1(object state)
{
var self = (ReadAllAsyncEnumerable)state;
self.parent.SingalCancellation(self.cancellationToken1);
}
static void CancellationCallback2(object state)
{
var self = (ReadAllAsyncEnumerable)state;
self.parent.SingalCancellation(self.cancellationToken2);
}
}
}
}
}

11
Runtime/Channel.cs.meta Normal file
View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 64b064347ca7a404494a996b072e2e29
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable CS0436
namespace System.Runtime.CompilerServices
{
internal sealed class AsyncMethodBuilderAttribute : Attribute
{
public Type BuilderType { get; }
public AsyncMethodBuilderAttribute(Type builderType)
{
BuilderType = builderType;
}
}
}

View File

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

View File

@ -0,0 +1,269 @@

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
namespace Cysharp.Threading.Tasks.CompilerServices
{
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder
{
IStateMachineRunnerPromise runnerPromise;
Exception ex;
// 1. Static Create method.
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncUniTaskMethodBuilder Create()
{
return default;
}
// 2. TaskLike Task property.
public UniTask Task
{
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (runnerPromise != null)
{
return runnerPromise.Task;
}
else if (ex != null)
{
return UniTask.FromException(ex);
}
else
{
return UniTask.CompletedTask;
}
}
}
// 3. SetException
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception)
{
if (runnerPromise == null)
{
ex = exception;
}
else
{
runnerPromise.SetException(exception);
}
}
// 4. SetResult
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult()
{
if (runnerPromise != null)
{
runnerPromise.SetResult();
}
}
// 5. AwaitOnCompleted
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.OnCompleted(runnerPromise.MoveNext);
}
// 6. AwaitUnsafeOnCompleted
[DebuggerHidden]
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
}
// 7. Start
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
// 8. SetStateMachine
[DebuggerHidden]
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
// don't use boxed stateMachine.
}
#if DEBUG || !UNITY_2018_3_OR_NEWER
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskMethodBuilder<T>
{
IStateMachineRunnerPromise<T> runnerPromise;
Exception ex;
T result;
// 1. Static Create method.
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncUniTaskMethodBuilder<T> Create()
{
return default;
}
// 2. TaskLike Task property.
public UniTask<T> Task
{
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (runnerPromise != null)
{
return runnerPromise.Task;
}
else if (ex != null)
{
return UniTask.FromException<T>(ex);
}
else
{
return UniTask.FromResult(result);
}
}
}
// 3. SetException
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception)
{
if (runnerPromise == null)
{
ex = exception;
}
else
{
runnerPromise.SetException(exception);
}
}
// 4. SetResult
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult(T result)
{
if (runnerPromise == null)
{
this.result = result;
}
else
{
runnerPromise.SetResult(result);
}
}
// 5. AwaitOnCompleted
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.OnCompleted(runnerPromise.MoveNext);
}
// 6. AwaitUnsafeOnCompleted
[DebuggerHidden]
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runnerPromise == null)
{
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref stateMachine, ref runnerPromise);
}
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
}
// 7. Start
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
// 8. SetStateMachine
[DebuggerHidden]
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
// don't use boxed stateMachine.
}
#if DEBUG || !UNITY_2018_3_OR_NEWER
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
}

View File

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

View File

@ -0,0 +1,137 @@

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
namespace Cysharp.Threading.Tasks.CompilerServices
{
[StructLayout(LayoutKind.Auto)]
public struct AsyncUniTaskVoidMethodBuilder
{
IStateMachineRunner runner;
// 1. Static Create method.
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AsyncUniTaskVoidMethodBuilder Create()
{
return default;
}
// 2. TaskLike Task property(void)
public UniTaskVoid Task
{
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return default;
}
}
// 3. SetException
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetException(Exception exception)
{
// runner is finished, return first.
if (runner != null)
{
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
#else
runner.Return();
#endif
runner = null;
}
UniTaskScheduler.PublishUnobservedTaskException(exception);
}
// 4. SetResult
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetResult()
{
// runner is finished, return.
if (runner != null)
{
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
#else
runner.Return();
#endif
runner = null;
}
}
// 5. AwaitOnCompleted
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runner == null)
{
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
}
awaiter.OnCompleted(runner.MoveNext);
}
// 6. AwaitUnsafeOnCompleted
[DebuggerHidden]
[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
if (runner == null)
{
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref stateMachine, ref runner);
}
awaiter.UnsafeOnCompleted(runner.MoveNext);
}
// 7. Start
[DebuggerHidden]
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
// 8. SetStateMachine
[DebuggerHidden]
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
// don't use boxed stateMachine.
}
#if DEBUG || !UNITY_2018_3_OR_NEWER
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
}

View File

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

View File

@ -0,0 +1,380 @@
#pragma warning disable CS1591
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Linq;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.CompilerServices
{
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
// but currently it is labeled `Won't Fix`.
internal interface IStateMachineRunner
{
Action MoveNext { get; }
void Return();
#if ENABLE_IL2CPP
Action ReturnAction { get; }
#endif
}
internal interface IStateMachineRunnerPromise : IUniTaskSource
{
Action MoveNext { get; }
UniTask Task { get; }
void SetResult();
void SetException(Exception exception);
}
internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T>
{
Action MoveNext { get; }
UniTask<T> Task { get; }
void SetResult(T result);
void SetException(Exception exception);
}
internal static class StateMachineUtility
{
// Get AsyncStateMachine internal state to check IL2CPP bug
public static int GetState(IAsyncStateMachine stateMachine)
{
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.First(x => x.Name.EndsWith("__state"));
return (int)info.GetValue(stateMachine);
}
}
internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
where TStateMachine : IAsyncStateMachine
{
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
#if ENABLE_IL2CPP
public Action ReturnAction { get; }
#endif
TStateMachine stateMachine;
public Action MoveNext { get; }
public AsyncUniTaskVoid()
{
MoveNext = Run;
#if ENABLE_IL2CPP
ReturnAction = Return;
#endif
}
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
{
if (!pool.TryPop(out var result))
{
result = new AsyncUniTaskVoid<TStateMachine>();
}
TaskTracker.TrackActiveTask(result, 3);
runnerFieldRef = result; // set runner before copied.
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
static AsyncUniTaskVoid()
{
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
}
AsyncUniTaskVoid<TStateMachine> nextNode;
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
public void Return()
{
TaskTracker.RemoveTracking(this);
stateMachine = default;
pool.TryPush(this);
}
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
stateMachine.MoveNext();
}
// dummy interface implementation for TaskTracker.
UniTaskStatus IUniTaskSource.GetStatus(short token)
{
return UniTaskStatus.Pending;
}
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
{
return UniTaskStatus.Pending;
}
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
{
}
void IUniTaskSource.GetResult(short token)
{
}
}
internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
where TStateMachine : IAsyncStateMachine
{
static TaskPool<AsyncUniTask<TStateMachine>> pool;
#if ENABLE_IL2CPP
readonly Action returnDelegate;
#endif
public Action MoveNext { get; }
TStateMachine stateMachine;
UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncUniTask()
{
MoveNext = Run;
#if ENABLE_IL2CPP
returnDelegate = Return;
#endif
}
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
{
if (!pool.TryPop(out var result))
{
result = new AsyncUniTask<TStateMachine>();
}
TaskTracker.TrackActiveTask(result, 3);
runnerPromiseFieldRef = result; // set runner before copied.
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
AsyncUniTask<TStateMachine> nextNode;
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
static AsyncUniTask()
{
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
}
void Return()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
pool.TryPush(this);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
return pool.TryPush(this);
}
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
stateMachine.MoveNext();
}
public UniTask Task
{
[DebuggerHidden]
get
{
return new UniTask(this, core.Version);
}
}
[DebuggerHidden]
public void SetResult()
{
core.TrySetResult(AsyncUnit.Default);
}
[DebuggerHidden]
public void SetException(Exception exception)
{
core.TrySetException(exception);
}
[DebuggerHidden]
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
#else
TryReturn();
#endif
}
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
}
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
where TStateMachine : IAsyncStateMachine
{
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
#if ENABLE_IL2CPP
readonly Action returnDelegate;
#endif
public Action MoveNext { get; }
TStateMachine stateMachine;
UniTaskCompletionSourceCore<T> core;
AsyncUniTask()
{
MoveNext = Run;
#if ENABLE_IL2CPP
returnDelegate = Return;
#endif
}
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
{
if (!pool.TryPop(out var result))
{
result = new AsyncUniTask<TStateMachine, T>();
}
TaskTracker.TrackActiveTask(result, 3);
runnerPromiseFieldRef = result; // set runner before copied.
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
AsyncUniTask<TStateMachine, T> nextNode;
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
static AsyncUniTask()
{
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
}
void Return()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
pool.TryPush(this);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
return pool.TryPush(this);
}
[DebuggerHidden]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
stateMachine.MoveNext();
}
public UniTask<T> Task
{
[DebuggerHidden]
get
{
return new UniTask<T>(this, core.Version);
}
}
[DebuggerHidden]
public void SetResult(T result)
{
core.TrySetResult(result);
}
[DebuggerHidden]
public void SetException(Exception exception)
{
core.TrySetException(exception);
}
[DebuggerHidden]
public T GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
#if ENABLE_IL2CPP
// workaround for IL2CPP bug.
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
#else
TryReturn();
#endif
}
}
[DebuggerHidden]
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
}
}

View File

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

View File

@ -0,0 +1,34 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
namespace Cysharp.Threading.Tasks
{
public static class EnumerableAsyncExtensions
{
// overload resolver - .Select(async x => { }) : IEnumerable<UniTask<T>>
public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, UniTask> selector)
{
return System.Linq.Enumerable.Select(source, selector);
}
public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, UniTask<TR>> selector)
{
return System.Linq.Enumerable.Select(source, selector);
}
public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, int, UniTask> selector)
{
return System.Linq.Enumerable.Select(source, selector);
}
public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, int, UniTask<TR>> selector)
{
return System.Linq.Enumerable.Select(source, selector);
}
}
}

View File

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

View File

@ -0,0 +1,287 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
using UnityEngine;
namespace Cysharp.Threading.Tasks
{
public static class EnumeratorAsyncExtensions
{
public static UniTask.Awaiter GetAwaiter<T>(this T enumerator)
where T : IEnumerator
{
var e = (IEnumerator)enumerator;
Error.ThrowArgumentNullException(e, nameof(enumerator));
return new UniTask(EnumeratorPromise.Create(e, PlayerLoopTiming.Update, CancellationToken.None, out var token), token).GetAwaiter();
}
public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, cancellationToken, out var token), token);
}
public static UniTask ToUniTask(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
{
Error.ThrowArgumentNullException(enumerator, nameof(enumerator));
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
}
public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
{
var source = AutoResetUniTaskCompletionSource.Create();
coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, source));
return source.Task;
}
static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
{
yield return coroutineRunner.StartCoroutine(inner);
source.TrySetResult();
}
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
{
static TaskPool<EnumeratorPromise> pool;
EnumeratorPromise nextNode;
public ref EnumeratorPromise NextNode => ref nextNode;
static EnumeratorPromise()
{
TaskPool.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
}
IEnumerator innerEnumerator;
CancellationToken cancellationToken;
int initialFrame;
bool loopRunning;
bool calledGetResult;
UniTaskCompletionSourceCore<object> core;
EnumeratorPromise()
{
}
public static IUniTaskSource Create(IEnumerator innerEnumerator, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new EnumeratorPromise();
}
TaskTracker.TrackActiveTask(result, 3);
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
result.cancellationToken = cancellationToken;
result.loopRunning = true;
result.calledGetResult = false;
result.initialFrame = -1;
token = result.core.Version;
// run immediately.
if (result.MoveNext())
{
PlayerLoopHelper.AddAction(timing, result);
}
return result;
}
public void GetResult(short token)
{
try
{
calledGetResult = true;
core.GetResult(token);
}
finally
{
if (!loopRunning)
{
TryReturn();
}
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (calledGetResult)
{
loopRunning = false;
TryReturn();
return false;
}
if (innerEnumerator == null) // invalid status, returned but loop running?
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
loopRunning = false;
core.TrySetCanceled(cancellationToken);
return false;
}
if (initialFrame == -1)
{
// Time can not touch in threadpool.
if (PlayerLoopHelper.IsMainThread)
{
initialFrame = Time.frameCount;
}
}
else if (initialFrame == Time.frameCount)
{
return true; // already executed in first frame, skip.
}
try
{
if (innerEnumerator.MoveNext())
{
return true;
}
}
catch (Exception ex)
{
loopRunning = false;
core.TrySetException(ex);
return false;
}
loopRunning = false;
core.TrySetResult(null);
return false;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
innerEnumerator = default;
cancellationToken = default;
return pool.TryPush(this);
}
// Unwrap YieldInstructions
static IEnumerator ConsumeEnumerator(IEnumerator enumerator)
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (current == null)
{
yield return null;
}
else if (current is CustomYieldInstruction cyi)
{
// WWW, WaitForSecondsRealtime
while (cyi.keepWaiting)
{
yield return null;
}
}
else if (current is YieldInstruction)
{
IEnumerator innerCoroutine = null;
switch (current)
{
case AsyncOperation ao:
innerCoroutine = UnwrapWaitAsyncOperation(ao);
break;
case WaitForSeconds wfs:
innerCoroutine = UnwrapWaitForSeconds(wfs);
break;
}
if (innerCoroutine != null)
{
while (innerCoroutine.MoveNext())
{
yield return null;
}
}
else
{
goto WARN;
}
}
else if (current is IEnumerator e3)
{
var e4 = ConsumeEnumerator(e3);
while (e4.MoveNext())
{
yield return null;
}
}
else
{
goto WARN;
}
continue;
WARN:
// WaitForEndOfFrame, WaitForFixedUpdate, others.
UnityEngine.Debug.LogWarning($"yield {current.GetType().Name} is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead.");
yield return null;
}
}
static readonly FieldInfo waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
{
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
var elapsed = 0.0f;
while (true)
{
yield return null;
elapsed += Time.deltaTime;
if (elapsed >= second)
{
break;
}
};
}
static IEnumerator UnwrapWaitAsyncOperation(AsyncOperation asyncOperation)
{
while (!asyncOperation.isDone)
{
yield return null;
}
}
}
}
}

View File

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

View File

@ -0,0 +1,14 @@

using System;
namespace Cysharp.Threading.Tasks
{
public static class ExceptionExtensions
{
public static bool IsOperationCanceledException(this Exception exception)
{
return exception is OperationCanceledException;
}
}
}

View File

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

8
Runtime/External.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3e874acee8398745b1dc3eddac09eaa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/External/Addressables.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a5b9231662e24c942b544bd85d4b39cb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,483 @@
// asmdef Version Defines, enabled when com.unity.addressables is imported.
#if UNITASK_ADDRESSABLE_SUPPORT
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Cysharp.Threading.Tasks
{
public static class AddressablesAsyncExtensions
{
#region AsyncOperationHandle
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
{
return ToUniTask(handle).GetAwaiter();
}
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
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), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
if (!handle.IsValid())
{
// autoReleaseHandle:true handle is invalid(immediately internal handle == null) so return completed.
return UniTask.CompletedTask;
}
if (handle.IsDone)
{
if (handle.Status == AsyncOperationStatus.Failed)
{
return UniTask.FromException(handle.OperationException);
}
return UniTask.CompletedTask;
}
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
}
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
{
AsyncOperationHandle handle;
Action<AsyncOperationHandle> continuationAction;
public AsyncOperationHandleAwaiter(AsyncOperationHandle handle)
{
this.handle = handle;
this.continuationAction = null;
}
public bool IsCompleted => handle.IsDone;
public void GetResult()
{
if (continuationAction != null)
{
handle.Completed -= continuationAction;
continuationAction = null;
}
if (handle.Status == AsyncOperationStatus.Failed)
{
var e = handle.OperationException;
handle = default;
ExceptionDispatchInfo.Capture(e).Throw();
}
var result = handle.Result;
handle = default;
}
public void OnCompleted(Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
handle.Completed += continuationAction;
}
}
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
{
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
AsyncOperationHandleConfiguredSource nextNode;
public ref AsyncOperationHandleConfiguredSource NextNode => ref nextNode;
static AsyncOperationHandleConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
}
readonly Action<AsyncOperationHandle> completedCallback;
AsyncOperationHandle handle;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
IProgress<float> progress;
bool autoReleaseWhenCanceled;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationHandleConfiguredSource()
{
completedCallback = HandleCompleted;
}
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCanceled, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncOperationHandleConfiguredSource();
}
result.handle = handle;
result.progress = progress;
result.cancellationToken = cancellationToken;
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.completedCallback;
token = result.core.Version;
return result;
}
void HandleCompleted(AsyncOperationHandle _)
{
if (handle.IsValid())
{
handle.Completed -= completedCallback;
}
if (completed)
{
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
{
core.TrySetResult(AsyncUnit.Default);
}
}
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);
}
public bool MoveNext()
{
if (completed)
{
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.GetDownloadStatus().Percent);
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
#endregion
#region AsyncOperationHandle_T
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
{
return ToUniTask(handle).GetAwaiter();
}
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
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), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
if (!handle.IsValid())
{
throw new Exception("Attempting to use an invalid operation handle");
}
if (handle.IsDone)
{
if (handle.Status == AsyncOperationStatus.Failed)
{
return UniTask.FromException<T>(handle.OperationException);
}
return UniTask.FromResult(handle.Result);
}
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
}
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
{
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
AsyncOperationHandleConfiguredSource<T> nextNode;
public ref AsyncOperationHandleConfiguredSource<T> NextNode => ref nextNode;
static AsyncOperationHandleConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
}
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()
{
completedCallback = HandleCompleted;
}
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)
{
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncOperationHandleConfiguredSource<T>();
}
result.handle = handle;
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.completedCallback;
token = result.core.Version;
return result;
}
void HandleCompleted(AsyncOperationHandle<T> argHandle)
{
if (handle.IsValid())
{
handle.Completed -= completedCallback;
}
if (completed)
{
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
{
core.TrySetResult(argHandle.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()
{
if (completed)
{
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.GetDownloadStatus().Percent);
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
#endregion
}
}
#endif

View File

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

View File

@ -0,0 +1,27 @@
{
"name": "UniTask.Runtime.Addressables",
"references": [
"UniTask.Runtime",
"Unity.ResourceManager"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.addressables",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
},
{
"name": "com.unity.addressables.cn",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 593a5b492d29ac6448b1ebf7f035ef33
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/External/DOTween.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25cb2f742bfeb1d48a4e65d3140b955d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,436 @@
// asmdef Version Defines, enabled when com.demigiant.dotween is imported.
#if UNITASK_DOTWEEN_SUPPORT
using Cysharp.Threading.Tasks.Internal;
using DG.Tweening;
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public enum TweenCancelBehaviour
{
Kill,
KillWithCompleteCallback,
Complete,
CompleteWithSequenceCallback,
CancelAwait,
// AndCancelAwait
KillAndCancelAwait,
KillWithCompleteCallbackAndCancelAwait,
CompleteAndCancelAwait,
CompleteWithSequenceCallbackAndCancelAwait
}
public static class DOTweenAsyncExtensions
{
enum CallbackType
{
Kill,
Complete,
Pause,
Play,
Rewind,
StepComplete
}
public static TweenAwaiter GetAwaiter(this Tween tween)
{
return new TweenAwaiter(tween);
}
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
}
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Kill, out var token), token);
}
public static UniTask AwaitForComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Complete, out var token), token);
}
public static UniTask AwaitForPause(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Pause, out var token), token);
}
public static UniTask AwaitForPlay(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Play, out var token), token);
}
public static UniTask AwaitForRewind(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Rewind, out var token), token);
}
public static UniTask AwaitForStepComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(tween, nameof(tween));
if (!tween.IsActive()) return UniTask.CompletedTask;
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.StepComplete, out var token), token);
}
public struct TweenAwaiter : ICriticalNotifyCompletion
{
readonly Tween tween;
// killed(non active) as completed.
public bool IsCompleted => !tween.IsActive();
public TweenAwaiter(Tween tween)
{
this.tween = tween;
}
public TweenAwaiter GetAwaiter()
{
return this;
}
public void GetResult()
{
}
public void OnCompleted(System.Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(System.Action continuation)
{
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
tween.onKill = PooledTweenCallback.Create(continuation);
}
}
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
{
static TaskPool<TweenConfiguredSource> pool;
TweenConfiguredSource nextNode;
public ref TweenConfiguredSource NextNode => ref nextNode;
static TweenConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
}
readonly TweenCallback onCompleteCallbackDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationRegistration;
CallbackType callbackType;
bool canceled;
TweenCallback originalCompleteAction;
UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource()
{
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
DoCancelBeforeCreate(tween, cancelBehaviour);
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new TweenConfiguredSource();
}
result.tween = tween;
result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken;
result.callbackType = callbackType;
result.canceled = false;
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;
return result;
}
void OnCompleteCallbackDelegate()
{
if (cancellationToken.IsCancellationRequested)
{
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
{
canceled = true;
}
}
if (canceled)
{
core.TrySetCanceled(cancellationToken);
}
else
{
originalCompleteAction?.Invoke();
core.TrySetResult(AsyncUnit.Default);
}
}
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
{
switch (tweenCancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallback:
tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
break;
}
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
TryReturn();
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationRegistration.Dispose();
RestoreOriginalCallback();
tween = default;
cancellationToken = default;
originalCompleteAction = default;
return pool.TryPush(this);
}
void RestoreOriginalCallback()
{
switch (callbackType)
{
case CallbackType.Kill:
tween.onKill = originalCompleteAction;
break;
case CallbackType.Complete:
tween.onComplete = originalCompleteAction;
break;
case CallbackType.Pause:
tween.onPause = originalCompleteAction;
break;
case CallbackType.Play:
tween.onPlay = originalCompleteAction;
break;
case CallbackType.Rewind:
tween.onRewind = originalCompleteAction;
break;
case CallbackType.StepComplete:
tween.onStepComplete = originalCompleteAction;
break;
default:
break;
}
}
}
}
sealed class PooledTweenCallback
{
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
readonly TweenCallback runDelegate;
Action continuation;
PooledTweenCallback()
{
runDelegate = Run;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TweenCallback Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new PooledTweenCallback();
}
item.continuation = continuation;
return item.runDelegate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run()
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.Enqueue(this);
call.Invoke();
}
}
}
}
#endif

View File

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

View File

@ -0,0 +1,22 @@
{
"name": "UniTask.Runtime.DOTween",
"references": [
"UniTask.Runtime",
"DOTween.Runtime.Modules"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.demigiant.dotween",
"expression": "",
"define": "UNITASK_DOTWEEN_SUPPORT"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 029c1c1b674aaae47a6841a0b89ad80e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/External/TextMeshPro.meta vendored Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f89da606bde9a4e4e94ae1189a029887
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,224 @@
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
}
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
}
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
}
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
}
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, false);
}
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken);
}
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, false);
}
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken);
}
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, false);
}
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, cancellationToken);
}
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, false);
}
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, cancellationToken);
}
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, false);
}
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, cancellationToken);
}
}
}
#endif

View File

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

View File

@ -0,0 +1,66 @@
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
var handlers = new (string name, string type)[] {
("ValueChanged", "string"),
("EndEdit", "string"),
("EndTextSelection", "(string, int, int)"),
("TextSelection", "(string, int, int)"),
("Deselect", "string"),
("Select", "string"),
("Submit", "string"),
};
Func<string, bool> shouldConvert = x => x.EndsWith("TextSelection");
Func<string, string> eventName = x => shouldConvert(x) ? $"new TextSelectionEventConverter(inputField.on{x})" : $"inputField.on{x}";
#>
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
<# foreach(var (name, type) in handlers) { #>
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), false);
}
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, false);
}
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
}
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, true).OnInvokeAsync();
}
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField)
{
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy());
}
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
{
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, cancellationToken);
}
<# } #>
}
}
#endif

View File

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

View File

@ -0,0 +1,130 @@
#if UNITASK_TEXTMESHPRO_SUPPORT
using System;
using System.Threading;
using TMPro;
using UnityEngine.Events;
namespace Cysharp.Threading.Tasks
{
public static partial class TextMeshProAsyncExtensions
{
// <string> -> Text
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (true)
{
bool moveNext;
try
{
moveNext = await e.MoveNextAsync();
repeat = false;
}
catch (Exception ex)
{
if (ex is OperationCanceledException) return;
if (rebindOnError && !repeat)
{
repeat = true;
goto BIND_AGAIN;
}
else
{
throw;
}
}
if (!moveNext) return;
text.text = e.Current;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
// <T> -> Text
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
public static void BindTo<T>(this AsyncReactiveProperty<T> source, TMP_Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (true)
{
bool moveNext;
try
{
moveNext = await e.MoveNextAsync();
repeat = false;
}
catch (Exception ex)
{
if (ex is OperationCanceledException) return;
if (rebindOnError && !repeat)
{
repeat = true;
goto BIND_AGAIN;
}
else
{
throw;
}
}
if (!moveNext) return;
text.text = e.Current.ToString();
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
}
}
#endif

View File

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

View File

@ -0,0 +1,22 @@
{
"name": "UniTask.Runtime.TextMeshPro",
"references": [
"UniTask.Runtime",
"Unity.TextMeshPro"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.textmeshpro",
"expression": "",
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
}
],
"noEngineReferences": false
}

View File

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

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public interface IUniTaskAsyncEnumerable<out T>
{
IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
}
public interface IUniTaskAsyncEnumerator<out T> : IUniTaskAsyncDisposable
{
T Current { get; }
UniTask<bool> MoveNextAsync();
}
public interface IUniTaskAsyncDisposable
{
UniTask DisposeAsync();
}
public interface IUniTaskOrderedAsyncEnumerable<TElement> : IUniTaskAsyncEnumerable<TElement>
{
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
}
public interface IConnectableUniTaskAsyncEnumerable<out T> : IUniTaskAsyncEnumerable<T>
{
IDisposable Connect();
}
// don't use AsyncGrouping.
//public interface IUniTaskAsyncGrouping<out TKey, out TElement> : IUniTaskAsyncEnumerable<TElement>
//{
// TKey Key { get; }
//}
public static class UniTaskAsyncEnumerableExtensions
{
public static UniTaskCancelableAsyncEnumerable<T> WithCancellation<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
return new UniTaskCancelableAsyncEnumerable<T>(source, cancellationToken);
}
}
[StructLayout(LayoutKind.Auto)]
public readonly struct UniTaskCancelableAsyncEnumerable<T>
{
private readonly IUniTaskAsyncEnumerable<T> enumerable;
private readonly CancellationToken cancellationToken;
internal UniTaskCancelableAsyncEnumerable(IUniTaskAsyncEnumerable<T> enumerable, CancellationToken cancellationToken)
{
this.enumerable = enumerable;
this.cancellationToken = cancellationToken;
}
public Enumerator GetAsyncEnumerator()
{
return new Enumerator(enumerable.GetAsyncEnumerator(cancellationToken));
}
[StructLayout(LayoutKind.Auto)]
public readonly struct Enumerator
{
private readonly IUniTaskAsyncEnumerator<T> enumerator;
internal Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public T Current => enumerator.Current;
public UniTask<bool> MoveNextAsync()
{
return enumerator.MoveNextAsync();
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
}
}
}

View File

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

127
Runtime/IUniTaskSource.cs Normal file
View File

@ -0,0 +1,127 @@
#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;
namespace Cysharp.Threading.Tasks
{
public enum UniTaskStatus
{
/// <summary>The operation has not yet completed.</summary>
Pending = 0,
/// <summary>The operation completed successfully.</summary>
Succeeded = 1,
/// <summary>The operation completed with an error.</summary>
Faulted = 2,
/// <summary>The operation completed due to cancellation.</summary>
Canceled = 3
}
// similar as IValueTaskSource
public interface IUniTaskSource
#if SUPPORT_VALUETASK
: System.Threading.Tasks.Sources.IValueTaskSource
#endif
{
UniTaskStatus GetStatus(short token);
void OnCompleted(Action<object> continuation, object state, short token);
void GetResult(short token);
UniTaskStatus UnsafeGetStatus(); // only for debug use.
#if SUPPORT_VALUETASK
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
{
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
}
void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)
{
((IUniTaskSource)this).GetResult(token);
}
void System.Threading.Tasks.Sources.IValueTaskSource.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
{
// ignore flags, always none.
((IUniTaskSource)this).OnCompleted(continuation, state, token);
}
#endif
}
public interface IUniTaskSource<out T> : IUniTaskSource
#if SUPPORT_VALUETASK
, System.Threading.Tasks.Sources.IValueTaskSource<T>
#endif
{
new T GetResult(short token);
#if SUPPORT_VALUETASK
new public UniTaskStatus GetStatus(short token)
{
return ((IUniTaskSource)this).GetStatus(token);
}
new public void OnCompleted(Action<object> continuation, object state, short token)
{
((IUniTaskSource)this).OnCompleted(continuation, state, token);
}
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource<T>.GetStatus(short token)
{
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
}
T System.Threading.Tasks.Sources.IValueTaskSource<T>.GetResult(short token)
{
return ((IUniTaskSource<T>)this).GetResult(token);
}
void System.Threading.Tasks.Sources.IValueTaskSource<T>.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
{
// ignore flags, always none.
((IUniTaskSource)this).OnCompleted(continuation, state, token);
}
#endif
}
public static class UniTaskStatusExtensions
{
/// <summary>status != Pending.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsCompleted(this UniTaskStatus status)
{
return status != UniTaskStatus.Pending;
}
/// <summary>status == Succeeded.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsCompletedSuccessfully(this UniTaskStatus status)
{
return status == UniTaskStatus.Succeeded;
}
/// <summary>status == Canceled.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsCanceled(this UniTaskStatus status)
{
return status == UniTaskStatus.Canceled;
}
/// <summary>status == Faulted.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsFaulted(this UniTaskStatus status)
{
return status == UniTaskStatus.Faulted;
}
}
}

View File

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

8
Runtime/Internal.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 633f49a8aafb6fa43894cd4646c71743
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,150 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Internal
{
// Same interface as System.Buffers.ArrayPool<T> but only provides Shared.
public sealed class ArrayPool<T>
{
// Same size as System.Buffers.DefaultArrayPool<T>
const int DefaultMaxNumberOfArraysPerBucket = 50;
static readonly T[] EmptyArray = new T[0];
public static readonly ArrayPool<T> Shared = new ArrayPool<T>();
readonly MinimumQueue<T[]>[] buckets;
readonly SpinLock[] locks;
ArrayPool()
{
// see: GetQueueIndex
buckets = new MinimumQueue<T[]>[18];
locks = new SpinLock[18];
for (int i = 0; i < buckets.Length; i++)
{
buckets[i] = new MinimumQueue<T[]>(4);
locks[i] = new SpinLock(false);
}
}
public T[] Rent(int minimumLength)
{
if (minimumLength < 0)
{
throw new ArgumentOutOfRangeException("minimumLength");
}
else if (minimumLength == 0)
{
return EmptyArray;
}
var size = CalculateSize(minimumLength);
var index = GetQueueIndex(size);
if (index != -1)
{
var q = buckets[index];
var lockTaken = false;
try
{
locks[index].Enter(ref lockTaken);
if (q.Count != 0)
{
return q.Dequeue();
}
}
finally
{
if (lockTaken) locks[index].Exit(false);
}
}
return new T[size];
}
public void Return(T[] array, bool clearArray = false)
{
if (array == null || array.Length == 0)
{
return;
}
var index = GetQueueIndex(array.Length);
if (index != -1)
{
if (clearArray)
{
Array.Clear(array, 0, array.Length);
}
var q = buckets[index];
var lockTaken = false;
try
{
locks[index].Enter(ref lockTaken);
if (q.Count > DefaultMaxNumberOfArraysPerBucket)
{
return;
}
q.Enqueue(array);
}
finally
{
if (lockTaken) locks[index].Exit(false);
}
}
}
static int CalculateSize(int size)
{
size--;
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size += 1;
if (size < 8)
{
size = 8;
}
return size;
}
static int GetQueueIndex(int size)
{
switch (size)
{
case 8: return 0;
case 16: return 1;
case 32: return 2;
case 64: return 3;
case 128: return 4;
case 256: return 5;
case 512: return 6;
case 1024: return 7;
case 2048: return 8;
case 4096: return 9;
case 8192: return 10;
case 16384: return 11;
case 32768: return 12;
case 65536: return 13;
case 131072: return 14;
case 262144: return 15;
case 524288: return 16;
case 1048576: return 17; // max array length
default:
return -1;
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f83ebad81fb89fb4882331616ca6d248
timeCreated: 1532361008
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,115 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
public static class ArrayPoolUtil
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureCapacity<T>(ref T[] array, int index, ArrayPool<T> pool)
{
if (array.Length <= index)
{
EnsureCapacityCore(ref array, index, pool);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void EnsureCapacityCore<T>(ref T[] array, int index, ArrayPool<T> pool)
{
if (array.Length <= index)
{
var newSize = array.Length * 2;
var newArray = pool.Rent((index < newSize) ? newSize : (index * 2));
Array.Copy(array, 0, newArray, 0, array.Length);
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<T>());
array = newArray;
}
}
public static RentArray<T> Materialize<T>(IEnumerable<T> source)
{
if (source is T[] array)
{
return new RentArray<T>(array, array.Length, null);
}
var defaultCount = 32;
if (source is ICollection<T> coll)
{
if (coll.Count == 0)
{
return new RentArray<T>(Array.Empty<T>(), 0, null);
}
defaultCount = coll.Count;
var pool = ArrayPool<T>.Shared;
var buffer = pool.Rent(defaultCount);
coll.CopyTo(buffer, 0);
return new RentArray<T>(buffer, coll.Count, pool);
}
else if (source is IReadOnlyCollection<T> rcoll)
{
defaultCount = rcoll.Count;
}
if (defaultCount == 0)
{
return new RentArray<T>(Array.Empty<T>(), 0, null);
}
{
var pool = ArrayPool<T>.Shared;
var index = 0;
var buffer = pool.Rent(defaultCount);
foreach (var item in source)
{
EnsureCapacity(ref buffer, index, pool);
buffer[index++] = item;
}
return new RentArray<T>(buffer, index, pool);
}
}
public struct RentArray<T> : IDisposable
{
public readonly T[] Array;
public readonly int Length;
ArrayPool<T> pool;
public RentArray(T[] array, int length, ArrayPool<T> pool)
{
this.Array = array;
this.Length = length;
this.pool = pool;
}
public void Dispose()
{
DisposeManually(!RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<T>());
}
public void DisposeManually(bool clearArray)
{
if (pool != null)
{
if (clearArray)
{
System.Array.Clear(Array, 0, Length);
}
pool.Return(Array, clearArray: false);
pool = null;
}
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 424cc208fb61d4e448b08fcfa0eee25e
timeCreated: 1532361007
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
internal static class ArrayUtil
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureCapacity<T>(ref T[] array, int index)
{
if (array.Length <= index)
{
EnsureCore(ref array, index);
}
}
// rare case, no inlining.
[MethodImpl(MethodImplOptions.NoInlining)]
static void EnsureCore<T>(ref T[] array, int index)
{
var newSize = array.Length * 2;
var newArray = new T[(index < newSize) ? newSize : (index * 2)];
Array.Copy(array, 0, newArray, 0, array.Length);
array = newArray;
}
/// <summary>
/// Optimizing utility to avoid .ToArray() that creates buffer copy(cut to just size).
/// </summary>
public static (T[] array, int length) Materialize<T>(IEnumerable<T> source)
{
if (source is T[] array)
{
return (array, array.Length);
}
var defaultCount = 4;
if (source is ICollection<T> coll)
{
defaultCount = coll.Count;
var buffer = new T[defaultCount];
coll.CopyTo(buffer, 0);
return (buffer, defaultCount);
}
else if (source is IReadOnlyCollection<T> rcoll)
{
defaultCount = rcoll.Count;
}
if (defaultCount == 0)
{
return (Array.Empty<T>(), 0);
}
{
var index = 0;
var buffer = new T[defaultCount];
foreach (var item in source)
{
EnsureCapacity(ref buffer, index);
buffer[index++] = item;
}
return (buffer, index);
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 23146a82ec99f2542a87971c8d3d7988
timeCreated: 1532361007
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,225 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Internal
{
internal sealed class ContinuationQueue
{
const int MaxArrayLength = 0X7FEFFFFF;
const int InitialSize = 16;
readonly PlayerLoopTiming timing;
SpinLock gate = new SpinLock(false);
bool dequing = false;
int actionListCount = 0;
Action[] actionList = new Action[InitialSize];
int waitingListCount = 0;
Action[] waitingList = new Action[InitialSize];
public ContinuationQueue(PlayerLoopTiming timing)
{
this.timing = timing;
}
public void Enqueue(Action continuation)
{
bool lockTaken = false;
try
{
gate.Enter(ref lockTaken);
if (dequing)
{
// Ensure Capacity
if (waitingList.Length == waitingListCount)
{
var newLength = waitingListCount * 2;
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
var newArray = new Action[newLength];
Array.Copy(waitingList, newArray, waitingListCount);
waitingList = newArray;
}
waitingList[waitingListCount] = continuation;
waitingListCount++;
}
else
{
// Ensure Capacity
if (actionList.Length == actionListCount)
{
var newLength = actionListCount * 2;
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
var newArray = new Action[newLength];
Array.Copy(actionList, newArray, actionListCount);
actionList = newArray;
}
actionList[actionListCount] = continuation;
actionListCount++;
}
}
finally
{
if (lockTaken) gate.Exit(false);
}
}
public int Clear()
{
var rest = actionListCount + waitingListCount;
actionListCount = 0;
actionList = new Action[InitialSize];
waitingListCount = 0;
waitingList = new Action[InitialSize];
return rest;
}
// delegate entrypoint.
public void Run()
{
// for debugging, create named stacktrace.
#if DEBUG
switch (timing)
{
case PlayerLoopTiming.Initialization:
Initialization();
break;
case PlayerLoopTiming.LastInitialization:
LastInitialization();
break;
case PlayerLoopTiming.EarlyUpdate:
EarlyUpdate();
break;
case PlayerLoopTiming.LastEarlyUpdate:
LastEarlyUpdate();
break;
case PlayerLoopTiming.FixedUpdate:
FixedUpdate();
break;
case PlayerLoopTiming.LastFixedUpdate:
LastFixedUpdate();
break;
case PlayerLoopTiming.PreUpdate:
PreUpdate();
break;
case PlayerLoopTiming.LastPreUpdate:
LastPreUpdate();
break;
case PlayerLoopTiming.Update:
Update();
break;
case PlayerLoopTiming.LastUpdate:
LastUpdate();
break;
case PlayerLoopTiming.PreLateUpdate:
PreLateUpdate();
break;
case PlayerLoopTiming.LastPreLateUpdate:
LastPreLateUpdate();
break;
case PlayerLoopTiming.PostLateUpdate:
PostLateUpdate();
break;
case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate();
break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
break;
case PlayerLoopTiming.LastTimeUpdate:
LastTimeUpdate();
break;
#endif
default:
break;
}
#else
RunCore();
#endif
}
void Initialization() => RunCore();
void LastInitialization() => RunCore();
void EarlyUpdate() => RunCore();
void LastEarlyUpdate() => RunCore();
void FixedUpdate() => RunCore();
void LastFixedUpdate() => RunCore();
void PreUpdate() => RunCore();
void LastPreUpdate() => RunCore();
void Update() => RunCore();
void LastUpdate() => RunCore();
void PreLateUpdate() => RunCore();
void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore();
#endif
[System.Diagnostics.DebuggerHidden]
void RunCore()
{
{
bool lockTaken = false;
try
{
gate.Enter(ref lockTaken);
if (actionListCount == 0) return;
dequing = true;
}
finally
{
if (lockTaken) gate.Exit(false);
}
}
for (int i = 0; i < actionListCount; i++)
{
var action = actionList[i];
actionList[i] = null;
try
{
action();
}
catch (Exception ex)
{
UnityEngine.Debug.LogException(ex);
}
}
{
bool lockTaken = false;
try
{
gate.Enter(ref lockTaken);
dequing = false;
var swapTempActionList = actionList;
actionListCount = waitingListCount;
actionList = waitingList;
waitingListCount = 0;
waitingList = swapTempActionList;
}
finally
{
if (lockTaken) gate.Exit(false);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,249 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;
namespace Cysharp.Threading.Tasks.Internal
{
internal static class DiagnosticsExtensions
{
static bool displayFilenames = true;
static readonly Regex typeBeautifyRegex = new Regex("`.+$", RegexOptions.Compiled);
static readonly Dictionary<Type, string> builtInTypeNames = new Dictionary<Type, string>
{
{ typeof(void), "void" },
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(float), "float" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(object), "object" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(string), "string" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
{ typeof(ushort), "ushort" },
{ typeof(Task), "Task" },
{ typeof(UniTask), "UniTask" },
{ typeof(UniTaskVoid), "UniTaskVoid" }
};
public static string CleanupAsyncStackTrace(this StackTrace stackTrace)
{
if (stackTrace == null) return "";
var sb = new StringBuilder();
for (int i = 0; i < stackTrace.FrameCount; i++)
{
var sf = stackTrace.GetFrame(i);
var mb = sf.GetMethod();
if (IgnoreLine(mb)) continue;
if (IsAsync(mb))
{
sb.Append("async ");
TryResolveStateMachineMethod(ref mb, out var decType);
}
// return type
if (mb is MethodInfo mi)
{
sb.Append(BeautifyType(mi.ReturnType, false));
sb.Append(" ");
}
// method name
sb.Append(BeautifyType(mb.DeclaringType, false));
if (!mb.IsConstructor)
{
sb.Append(".");
}
sb.Append(mb.Name);
if (mb.IsGenericMethod)
{
sb.Append("<");
foreach (var item in mb.GetGenericArguments())
{
sb.Append(BeautifyType(item, true));
}
sb.Append(">");
}
// parameter
sb.Append("(");
sb.Append(string.Join(", ", mb.GetParameters().Select(p => BeautifyType(p.ParameterType, true) + " " + p.Name)));
sb.Append(")");
// file name
if (displayFilenames && (sf.GetILOffset() != -1))
{
String fileName = null;
try
{
fileName = sf.GetFileName();
}
catch (NotSupportedException)
{
displayFilenames = false;
}
catch (SecurityException)
{
displayFilenames = false;
}
if (fileName != null)
{
sb.Append(' ');
sb.AppendFormat(CultureInfo.InvariantCulture, "(at {0})", AppendHyperLink(fileName, sf.GetFileLineNumber().ToString()));
}
}
sb.AppendLine();
}
return sb.ToString();
}
static bool IsAsync(MethodBase methodInfo)
{
var declareType = methodInfo.DeclaringType;
return typeof(IAsyncStateMachine).IsAssignableFrom(declareType);
}
// code from Ben.Demystifier/EnhancedStackTrace.Frame.cs
static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType)
{
declaringType = method.DeclaringType;
var parentType = declaringType.DeclaringType;
if (parentType == null)
{
return false;
}
var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
if (methods == null)
{
return false;
}
foreach (var candidateMethod in methods)
{
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(false);
if (attributes == null)
{
continue;
}
foreach (var asma in attributes)
{
if (asma.StateMachineType == declaringType)
{
method = candidateMethod;
declaringType = candidateMethod.DeclaringType;
// Mark the iterator as changed; so it gets the + annotation of the original method
// async statemachines resolve directly to their builder methods so aren't marked as changed
return asma is IteratorStateMachineAttribute;
}
}
}
return false;
}
static string BeautifyType(Type t, bool shortName)
{
if (builtInTypeNames.TryGetValue(t, out var builtin))
{
return builtin;
}
if (t.IsGenericParameter) return t.Name;
if (t.IsArray) return BeautifyType(t.GetElementType(), shortName) + "[]";
if (t.FullName?.StartsWith("System.ValueTuple") ?? false)
{
return "(" + string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true))) + ")";
}
if (!t.IsGenericType) return shortName ? t.Name : t.FullName.Replace("Cysharp.Threading.Tasks.Triggers.", "").Replace("Cysharp.Threading.Tasks.Internal.", "").Replace("Cysharp.Threading.Tasks.", "") ?? t.Name;
var innerFormat = string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true)));
var genericType = t.GetGenericTypeDefinition().FullName;
if (genericType == "System.Threading.Tasks.Task`1")
{
genericType = "Task";
}
return typeBeautifyRegex.Replace(genericType, "").Replace("Cysharp.Threading.Tasks.Triggers.", "").Replace("Cysharp.Threading.Tasks.Internal.", "").Replace("Cysharp.Threading.Tasks.", "") + "<" + innerFormat + ">";
}
static bool IgnoreLine(MethodBase methodInfo)
{
var declareType = methodInfo.DeclaringType.FullName;
if (declareType == "System.Threading.ExecutionContext")
{
return true;
}
else if (declareType.StartsWith("System.Runtime.CompilerServices"))
{
return true;
}
else if (declareType.StartsWith("Cysharp.Threading.Tasks.CompilerServices"))
{
return true;
}
else if (declareType == "System.Threading.Tasks.AwaitTaskContinuation")
{
return true;
}
else if (declareType.StartsWith("System.Threading.Tasks.Task"))
{
return true;
}
else if (declareType.StartsWith("Cysharp.Threading.Tasks.UniTaskCompletionSourceCore"))
{
return true;
}
else if (declareType.StartsWith("Cysharp.Threading.Tasks.AwaiterActions"))
{
return true;
}
return false;
}
static string AppendHyperLink(string path, string line)
{
var fi = new FileInfo(path);
if (fi.Directory == null)
{
return fi.Name;
}
else
{
var fname = fi.FullName.Replace(Path.DirectorySeparatorChar, '/').Replace(PlayerLoopHelper.ApplicationDataPath, "");
var withAssetsPath = "Assets/" + fname;
return "<a href=\"" + withAssetsPath + "\" line=\"" + line + "\">" + withAssetsPath + ":" + line + "</a>";
}
}
}
}

View File

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

79
Runtime/Internal/Error.cs Normal file
View File

@ -0,0 +1,79 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
public static class Error
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowArgumentNullException<T>(T value, string paramName)
where T : class
{
if (value == null) ThrowArgumentNullExceptionCore(paramName);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void ThrowArgumentNullExceptionCore(string paramName)
{
throw new ArgumentNullException(paramName);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Exception ArgumentOutOfRange(string paramName)
{
return new ArgumentOutOfRangeException(paramName);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Exception NoElements()
{
return new InvalidOperationException("Source sequence doesn't contain any elements.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Exception MoreThanOneElement()
{
return new InvalidOperationException("Source sequence contains more than one element.");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowArgumentException(string message)
{
throw new ArgumentException(message);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNotYetCompleted()
{
throw new InvalidOperationException("Not yet completed.");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static T ThrowNotYetCompleted<T>()
{
throw new InvalidOperationException("Not yet completed.");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowWhenContinuationIsAlreadyRegistered<T>(T continuationField)
where T : class
{
if (continuationField != null) ThrowInvalidOperationExceptionCore("continuation is already registered.");
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void ThrowInvalidOperationExceptionCore(string message)
{
throw new InvalidOperationException(message);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowOperationCanceledException()
{
throw new OperationCanceledException();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5f39f495294d4604b8082202faf98554
timeCreated: 1532361007
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,112 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
// optimized version of Standard Queue<T>.
internal class MinimumQueue<T>
{
const int MinimumGrow = 4;
const int GrowFactor = 200;
T[] array;
int head;
int tail;
int size;
public MinimumQueue(int capacity)
{
if (capacity < 0) throw new ArgumentOutOfRangeException("capacity");
array = new T[capacity];
head = tail = size = 0;
}
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return size; }
}
public T Peek()
{
if (size == 0) ThrowForEmptyQueue();
return array[head];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Enqueue(T item)
{
if (size == array.Length)
{
Grow();
}
array[tail] = item;
MoveNext(ref tail);
size++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Dequeue()
{
if (size == 0) ThrowForEmptyQueue();
int head = this.head;
T[] array = this.array;
T removed = array[head];
array[head] = default(T);
MoveNext(ref this.head);
size--;
return removed;
}
void Grow()
{
int newcapacity = (int)((long)array.Length * (long)GrowFactor / 100);
if (newcapacity < array.Length + MinimumGrow)
{
newcapacity = array.Length + MinimumGrow;
}
SetCapacity(newcapacity);
}
void SetCapacity(int capacity)
{
T[] newarray = new T[capacity];
if (size > 0)
{
if (head < tail)
{
Array.Copy(array, head, newarray, 0, size);
}
else
{
Array.Copy(array, head, newarray, 0, array.Length - head);
Array.Copy(array, 0, newarray, array.Length - head, tail);
}
}
array = newarray;
head = 0;
tail = (size == capacity) ? 0 : size;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MoveNext(ref int index)
{
int tmp = index + 1;
if (tmp == array.Length)
{
tmp = 0;
}
index = tmp;
}
void ThrowForEmptyQueue()
{
throw new InvalidOperationException("EmptyQueue");
}
}
}

View File

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

View File

@ -0,0 +1,260 @@

using System;
using UnityEngine;
namespace Cysharp.Threading.Tasks.Internal
{
internal sealed class PlayerLoopRunner
{
const int InitialSize = 16;
readonly PlayerLoopTiming timing;
readonly object runningAndQueueLock = new object();
readonly object arrayLock = new object();
readonly Action<Exception> unhandledExceptionCallback;
int tail = 0;
bool running = false;
IPlayerLoopItem[] loopItems = new IPlayerLoopItem[InitialSize];
MinimumQueue<IPlayerLoopItem> waitQueue = new MinimumQueue<IPlayerLoopItem>(InitialSize);
public PlayerLoopRunner(PlayerLoopTiming timing)
{
this.unhandledExceptionCallback = ex => Debug.LogException(ex);
this.timing = timing;
}
public void AddAction(IPlayerLoopItem item)
{
lock (runningAndQueueLock)
{
if (running)
{
waitQueue.Enqueue(item);
return;
}
}
lock (arrayLock)
{
// Ensure Capacity
if (loopItems.Length == tail)
{
Array.Resize(ref loopItems, checked(tail * 2));
}
loopItems[tail++] = item;
}
}
public int Clear()
{
lock (arrayLock)
{
var rest = 0;
for (var index = 0; index < loopItems.Length; index++)
{
if (loopItems[index] != null)
{
rest++;
}
loopItems[index] = null;
}
tail = 0;
return rest;
}
}
// delegate entrypoint.
public void Run()
{
// for debugging, create named stacktrace.
#if DEBUG
switch (timing)
{
case PlayerLoopTiming.Initialization:
Initialization();
break;
case PlayerLoopTiming.LastInitialization:
LastInitialization();
break;
case PlayerLoopTiming.EarlyUpdate:
EarlyUpdate();
break;
case PlayerLoopTiming.LastEarlyUpdate:
LastEarlyUpdate();
break;
case PlayerLoopTiming.FixedUpdate:
FixedUpdate();
break;
case PlayerLoopTiming.LastFixedUpdate:
LastFixedUpdate();
break;
case PlayerLoopTiming.PreUpdate:
PreUpdate();
break;
case PlayerLoopTiming.LastPreUpdate:
LastPreUpdate();
break;
case PlayerLoopTiming.Update:
Update();
break;
case PlayerLoopTiming.LastUpdate:
LastUpdate();
break;
case PlayerLoopTiming.PreLateUpdate:
PreLateUpdate();
break;
case PlayerLoopTiming.LastPreLateUpdate:
LastPreLateUpdate();
break;
case PlayerLoopTiming.PostLateUpdate:
PostLateUpdate();
break;
case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate();
break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
break;
case PlayerLoopTiming.LastTimeUpdate:
LastTimeUpdate();
break;
#endif
default:
break;
}
#else
RunCore();
#endif
}
void Initialization() => RunCore();
void LastInitialization() => RunCore();
void EarlyUpdate() => RunCore();
void LastEarlyUpdate() => RunCore();
void FixedUpdate() => RunCore();
void LastFixedUpdate() => RunCore();
void PreUpdate() => RunCore();
void LastPreUpdate() => RunCore();
void Update() => RunCore();
void LastUpdate() => RunCore();
void PreLateUpdate() => RunCore();
void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore();
#endif
[System.Diagnostics.DebuggerHidden]
void RunCore()
{
lock (runningAndQueueLock)
{
running = true;
}
lock (arrayLock)
{
var j = tail - 1;
for (int i = 0; i < loopItems.Length; i++)
{
var action = loopItems[i];
if (action != null)
{
try
{
if (!action.MoveNext())
{
loopItems[i] = null;
}
else
{
continue; // next i
}
}
catch (Exception ex)
{
loopItems[i] = null;
try
{
unhandledExceptionCallback(ex);
}
catch { }
}
}
// find null, loop from tail
while (i < j)
{
var fromTail = loopItems[j];
if (fromTail != null)
{
try
{
if (!fromTail.MoveNext())
{
loopItems[j] = null;
j--;
continue; // next j
}
else
{
// swap
loopItems[i] = fromTail;
loopItems[j] = null;
j--;
goto NEXT_LOOP; // next i
}
}
catch (Exception ex)
{
loopItems[j] = null;
j--;
try
{
unhandledExceptionCallback(ex);
}
catch { }
continue; // next j
}
}
else
{
j--;
}
}
tail = i; // loop end
break; // LOOP END
NEXT_LOOP:
continue;
}
lock (runningAndQueueLock)
{
running = false;
while (waitQueue.Count != 0)
{
if (loopItems.Length == tail)
{
Array.Resize(ref loopItems, checked(tail * 2));
}
loopItems[tail++] = waitQueue.Dequeue();
}
}
}
}
}
}

View File

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

View File

@ -0,0 +1,50 @@
using System;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
internal sealed class PooledDelegate<T> : ITaskPoolNode<PooledDelegate<T>>
{
static TaskPool<PooledDelegate<T>> pool;
PooledDelegate<T> nextNode;
public ref PooledDelegate<T> NextNode => ref nextNode;
static PooledDelegate()
{
TaskPool.RegisterSizeGetter(typeof(PooledDelegate<T>), () => pool.Size);
}
readonly Action<T> runDelegate;
Action continuation;
PooledDelegate()
{
runDelegate = Run;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Action<T> Create(Action continuation)
{
if (!pool.TryPop(out var item))
{
item = new PooledDelegate<T>();
}
item.continuation = continuation;
return item.runDelegate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void Run(T _)
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.TryPush(this);
call.Invoke();
}
}
}
}

View File

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

View File

@ -0,0 +1,64 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
#if UNITY_2018_3_OR_NEWER
using UnityEngine;
#endif
namespace Cysharp.Threading.Tasks.Internal
{
public static class RuntimeHelpersAbstraction
{
// If we can use RuntimeHelpers.IsReferenceOrContainsReferences(.NET Core 2.0), use it.
public static bool IsWellKnownNoReferenceContainsType<T>()
{
return WellKnownNoReferenceContainsType<T>.IsWellKnownType;
}
static bool WellKnownNoReferenceContainsTypeInitialize(Type t)
{
// The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single.
if (t.IsPrimitive) return true;
if (t.IsEnum) return true;
if (t == typeof(DateTime)) return true;
if (t == typeof(DateTimeOffset)) return true;
if (t == typeof(Guid)) return true;
if (t == typeof(decimal)) return true;
// unwrap nullable
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return WellKnownNoReferenceContainsTypeInitialize(t.GetGenericArguments()[0]);
}
#if UNITY_2018_3_OR_NEWER
// or add other wellknown types(Vector, etc...) here
if (t == typeof(Vector2)) return true;
if (t == typeof(Vector3)) return true;
if (t == typeof(Vector4)) return true;
if (t == typeof(Color)) return true;
if (t == typeof(Rect)) return true;
if (t == typeof(Bounds)) return true;
if (t == typeof(Quaternion)) return true;
if (t == typeof(Vector2Int)) return true;
if (t == typeof(Vector3Int)) return true;
#endif
return false;
}
static class WellKnownNoReferenceContainsType<T>
{
public static readonly bool IsWellKnownType;
static WellKnownNoReferenceContainsType()
{
IsWellKnownType = WellKnownNoReferenceContainsTypeInitialize(typeof(T));
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 94975e4d4e0c0ea4ba787d3872ce9bb4
timeCreated: 1532361007
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
public static class StateTuple
{
public static StateTuple<T1> Create<T1>(T1 item1)
{
return StatePool<T1>.Create(item1);
}
public static StateTuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
{
return StatePool<T1, T2>.Create(item1, item2);
}
public static StateTuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
{
return StatePool<T1, T2, T3>.Create(item1, item2, item3);
}
}
public class StateTuple<T1> : IDisposable
{
public T1 Item1;
public void Deconstruct(out T1 item1)
{
item1 = this.Item1;
}
public void Dispose()
{
StatePool<T1>.Return(this);
}
}
internal static class StatePool<T1>
{
static readonly ConcurrentQueue<StateTuple<T1>> queue = new ConcurrentQueue<StateTuple<T1>>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StateTuple<T1> Create(T1 item1)
{
if (queue.TryDequeue(out var value))
{
value.Item1 = item1;
return value;
}
return new StateTuple<T1> { Item1 = item1 };
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(StateTuple<T1> tuple)
{
tuple.Item1 = default;
queue.Enqueue(tuple);
}
}
public class StateTuple<T1, T2> : IDisposable
{
public T1 Item1;
public T2 Item2;
public void Deconstruct(out T1 item1, out T2 item2)
{
item1 = this.Item1;
item2 = this.Item2;
}
public void Dispose()
{
StatePool<T1, T2>.Return(this);
}
}
internal static class StatePool<T1, T2>
{
static readonly ConcurrentQueue<StateTuple<T1, T2>> queue = new ConcurrentQueue<StateTuple<T1, T2>>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StateTuple<T1, T2> Create(T1 item1, T2 item2)
{
if (queue.TryDequeue(out var value))
{
value.Item1 = item1;
value.Item2 = item2;
return value;
}
return new StateTuple<T1, T2> { Item1 = item1, Item2 = item2 };
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(StateTuple<T1, T2> tuple)
{
tuple.Item1 = default;
tuple.Item2 = default;
queue.Enqueue(tuple);
}
}
public class StateTuple<T1, T2, T3> : IDisposable
{
public T1 Item1;
public T2 Item2;
public T3 Item3;
public void Deconstruct(out T1 item1, out T2 item2, out T3 item3)
{
item1 = this.Item1;
item2 = this.Item2;
item3 = this.Item3;
}
public void Dispose()
{
StatePool<T1, T2, T3>.Return(this);
}
}
internal static class StatePool<T1, T2, T3>
{
static readonly ConcurrentQueue<StateTuple<T1, T2, T3>> queue = new ConcurrentQueue<StateTuple<T1, T2, T3>>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StateTuple<T1, T2, T3> Create(T1 item1, T2 item2, T3 item3)
{
if (queue.TryDequeue(out var value))
{
value.Item1 = item1;
value.Item2 = item2;
value.Item3 = item3;
return value;
}
return new StateTuple<T1, T2, T3> { Item1 = item1, Item2 = item2, Item3 = item3 };
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(StateTuple<T1, T2, T3> tuple)
{
tuple.Item1 = default;
tuple.Item2 = default;
tuple.Item3 = default;
queue.Enqueue(tuple);
}
}
}

View File

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

View File

@ -0,0 +1,178 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks
{
// public for add user custom.
public static class TaskTracker
{
#if UNITY_EDITOR
static int trackingId = 0;
public const string EnableAutoReloadKey = "UniTaskTrackerWindow_EnableAutoReloadKey";
public const string EnableTrackingKey = "UniTaskTrackerWindow_EnableTrackingKey";
public const string EnableStackTraceKey = "UniTaskTrackerWindow_EnableStackTraceKey";
public static class EditorEnableState
{
static bool enableAutoReload;
public static bool EnableAutoReload
{
get { return enableAutoReload; }
set
{
enableAutoReload = value;
UnityEditor.EditorPrefs.SetBool(EnableAutoReloadKey, value);
}
}
static bool enableTracking;
public static bool EnableTracking
{
get { return enableTracking; }
set
{
enableTracking = value;
UnityEditor.EditorPrefs.SetBool(EnableTrackingKey, value);
}
}
static bool enableStackTrace;
public static bool EnableStackTrace
{
get { return enableStackTrace; }
set
{
enableStackTrace = value;
UnityEditor.EditorPrefs.SetBool(EnableStackTraceKey, value);
}
}
}
#endif
static List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>> listPool = new List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>>();
static readonly WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)> tracking = new WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>();
[Conditional("UNITY_EDITOR")]
public static void TrackActiveTask(IUniTaskSource task, int skipFrame)
{
#if UNITY_EDITOR
dirty = true;
if (!EditorEnableState.EnableTracking) return;
var stackTrace = EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, true).CleanupAsyncStackTrace() : "";
string typeName;
if (EditorEnableState.EnableStackTrace)
{
var sb = new StringBuilder();
TypeBeautify(task.GetType(), sb);
typeName = sb.ToString();
}
else
{
typeName = task.GetType().Name;
}
tracking.TryAdd(task, (typeName, Interlocked.Increment(ref trackingId), DateTime.UtcNow, stackTrace));
#endif
}
[Conditional("UNITY_EDITOR")]
public static void RemoveTracking(IUniTaskSource task)
{
#if UNITY_EDITOR
dirty = true;
if (!EditorEnableState.EnableTracking) return;
var success = tracking.TryRemove(task);
#endif
}
static bool dirty;
public static bool CheckAndResetDirty()
{
var current = dirty;
dirty = false;
return current;
}
/// <summary>(trackingId, awaiterType, awaiterStatus, createdTime, stackTrace)</summary>
public static void ForEachActiveTask(Action<int, string, UniTaskStatus, DateTime, string> action)
{
lock (listPool)
{
var count = tracking.ToList(ref listPool, clear: false);
try
{
for (int i = 0; i < count; i++)
{
action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
listPool[i] = default;
}
}
catch
{
listPool.Clear();
throw;
}
}
}
static void TypeBeautify(Type type, StringBuilder sb)
{
if (type.IsNested)
{
// TypeBeautify(type.DeclaringType, sb);
sb.Append(type.DeclaringType.Name.ToString());
sb.Append(".");
}
if (type.IsGenericType)
{
var genericsStart = type.Name.IndexOf("`");
if (genericsStart != -1)
{
sb.Append(type.Name.Substring(0, genericsStart));
}
else
{
sb.Append(type.Name);
}
sb.Append("<");
var first = true;
foreach (var item in type.GetGenericArguments())
{
if (!first)
{
sb.Append(", ");
}
first = false;
TypeBeautify(item, sb);
}
sb.Append(">");
}
else
{
sb.Append(type.Name);
}
}
//static string RemoveUniTaskNamespace(string str)
//{
// return str.Replace("Cysharp.Threading.Tasks.CompilerServices", "")
// .Replace("Cysharp.Threading.Tasks.Linq", "")
// .Replace("Cysharp.Threading.Tasks", "");
//}
}
}

View File

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

View File

@ -0,0 +1,267 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cysharp.Threading.Tasks.Internal
{
public static class UnityEqualityComparer
{
public static readonly IEqualityComparer<Vector2> Vector2 = new Vector2EqualityComparer();
public static readonly IEqualityComparer<Vector3> Vector3 = new Vector3EqualityComparer();
public static readonly IEqualityComparer<Vector4> Vector4 = new Vector4EqualityComparer();
public static readonly IEqualityComparer<Color> Color = new ColorEqualityComparer();
public static readonly IEqualityComparer<Color32> Color32 = new Color32EqualityComparer();
public static readonly IEqualityComparer<Rect> Rect = new RectEqualityComparer();
public static readonly IEqualityComparer<Bounds> Bounds = new BoundsEqualityComparer();
public static readonly IEqualityComparer<Quaternion> Quaternion = new QuaternionEqualityComparer();
static readonly RuntimeTypeHandle vector2Type = typeof(Vector2).TypeHandle;
static readonly RuntimeTypeHandle vector3Type = typeof(Vector3).TypeHandle;
static readonly RuntimeTypeHandle vector4Type = typeof(Vector4).TypeHandle;
static readonly RuntimeTypeHandle colorType = typeof(Color).TypeHandle;
static readonly RuntimeTypeHandle color32Type = typeof(Color32).TypeHandle;
static readonly RuntimeTypeHandle rectType = typeof(Rect).TypeHandle;
static readonly RuntimeTypeHandle boundsType = typeof(Bounds).TypeHandle;
static readonly RuntimeTypeHandle quaternionType = typeof(Quaternion).TypeHandle;
#if UNITY_2017_2_OR_NEWER
public static readonly IEqualityComparer<Vector2Int> Vector2Int = new Vector2IntEqualityComparer();
public static readonly IEqualityComparer<Vector3Int> Vector3Int = new Vector3IntEqualityComparer();
public static readonly IEqualityComparer<RangeInt> RangeInt = new RangeIntEqualityComparer();
public static readonly IEqualityComparer<RectInt> RectInt = new RectIntEqualityComparer();
public static readonly IEqualityComparer<BoundsInt> BoundsInt = new BoundsIntEqualityComparer();
static readonly RuntimeTypeHandle vector2IntType = typeof(Vector2Int).TypeHandle;
static readonly RuntimeTypeHandle vector3IntType = typeof(Vector3Int).TypeHandle;
static readonly RuntimeTypeHandle rangeIntType = typeof(RangeInt).TypeHandle;
static readonly RuntimeTypeHandle rectIntType = typeof(RectInt).TypeHandle;
static readonly RuntimeTypeHandle boundsIntType = typeof(BoundsInt).TypeHandle;
#endif
static class Cache<T>
{
public static readonly IEqualityComparer<T> Comparer;
static Cache()
{
var comparer = GetDefaultHelper(typeof(T));
if (comparer == null)
{
Comparer = EqualityComparer<T>.Default;
}
else
{
Comparer = (IEqualityComparer<T>)comparer;
}
}
}
public static IEqualityComparer<T> GetDefault<T>()
{
return Cache<T>.Comparer;
}
static object GetDefaultHelper(Type type)
{
var t = type.TypeHandle;
if (t.Equals(vector2Type)) return (object)UnityEqualityComparer.Vector2;
if (t.Equals(vector3Type)) return (object)UnityEqualityComparer.Vector3;
if (t.Equals(vector4Type)) return (object)UnityEqualityComparer.Vector4;
if (t.Equals(colorType)) return (object)UnityEqualityComparer.Color;
if (t.Equals(color32Type)) return (object)UnityEqualityComparer.Color32;
if (t.Equals(rectType)) return (object)UnityEqualityComparer.Rect;
if (t.Equals(boundsType)) return (object)UnityEqualityComparer.Bounds;
if (t.Equals(quaternionType)) return (object)UnityEqualityComparer.Quaternion;
#if UNITY_2017_2_OR_NEWER
if (t.Equals(vector2IntType)) return (object)UnityEqualityComparer.Vector2Int;
if (t.Equals(vector3IntType)) return (object)UnityEqualityComparer.Vector3Int;
if (t.Equals(rangeIntType)) return (object)UnityEqualityComparer.RangeInt;
if (t.Equals(rectIntType)) return (object)UnityEqualityComparer.RectInt;
if (t.Equals(boundsIntType)) return (object)UnityEqualityComparer.BoundsInt;
#endif
return null;
}
sealed class Vector2EqualityComparer : IEqualityComparer<Vector2>
{
public bool Equals(Vector2 self, Vector2 vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y);
}
public int GetHashCode(Vector2 obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2;
}
}
sealed class Vector3EqualityComparer : IEqualityComparer<Vector3>
{
public bool Equals(Vector3 self, Vector3 vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z);
}
public int GetHashCode(Vector3 obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2;
}
}
sealed class Vector4EqualityComparer : IEqualityComparer<Vector4>
{
public bool Equals(Vector4 self, Vector4 vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z) && self.w.Equals(vector.w);
}
public int GetHashCode(Vector4 obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2 ^ obj.w.GetHashCode() >> 1;
}
}
sealed class ColorEqualityComparer : IEqualityComparer<Color>
{
public bool Equals(Color self, Color other)
{
return self.r.Equals(other.r) && self.g.Equals(other.g) && self.b.Equals(other.b) && self.a.Equals(other.a);
}
public int GetHashCode(Color obj)
{
return obj.r.GetHashCode() ^ obj.g.GetHashCode() << 2 ^ obj.b.GetHashCode() >> 2 ^ obj.a.GetHashCode() >> 1;
}
}
sealed class RectEqualityComparer : IEqualityComparer<Rect>
{
public bool Equals(Rect self, Rect other)
{
return self.x.Equals(other.x) && self.width.Equals(other.width) && self.y.Equals(other.y) && self.height.Equals(other.height);
}
public int GetHashCode(Rect obj)
{
return obj.x.GetHashCode() ^ obj.width.GetHashCode() << 2 ^ obj.y.GetHashCode() >> 2 ^ obj.height.GetHashCode() >> 1;
}
}
sealed class BoundsEqualityComparer : IEqualityComparer<Bounds>
{
public bool Equals(Bounds self, Bounds vector)
{
return self.center.Equals(vector.center) && self.extents.Equals(vector.extents);
}
public int GetHashCode(Bounds obj)
{
return obj.center.GetHashCode() ^ obj.extents.GetHashCode() << 2;
}
}
sealed class QuaternionEqualityComparer : IEqualityComparer<Quaternion>
{
public bool Equals(Quaternion self, Quaternion vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z) && self.w.Equals(vector.w);
}
public int GetHashCode(Quaternion obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2 ^ obj.w.GetHashCode() >> 1;
}
}
sealed class Color32EqualityComparer : IEqualityComparer<Color32>
{
public bool Equals(Color32 self, Color32 vector)
{
return self.a.Equals(vector.a) && self.r.Equals(vector.r) && self.g.Equals(vector.g) && self.b.Equals(vector.b);
}
public int GetHashCode(Color32 obj)
{
return obj.a.GetHashCode() ^ obj.r.GetHashCode() << 2 ^ obj.g.GetHashCode() >> 2 ^ obj.b.GetHashCode() >> 1;
}
}
#if UNITY_2017_2_OR_NEWER
sealed class Vector2IntEqualityComparer : IEqualityComparer<Vector2Int>
{
public bool Equals(Vector2Int self, Vector2Int vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y);
}
public int GetHashCode(Vector2Int obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2;
}
}
sealed class Vector3IntEqualityComparer : IEqualityComparer<Vector3Int>
{
public static readonly Vector3IntEqualityComparer Default = new Vector3IntEqualityComparer();
public bool Equals(Vector3Int self, Vector3Int vector)
{
return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z);
}
public int GetHashCode(Vector3Int obj)
{
return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2;
}
}
sealed class RangeIntEqualityComparer : IEqualityComparer<RangeInt>
{
public bool Equals(RangeInt self, RangeInt vector)
{
return self.start.Equals(vector.start) && self.length.Equals(vector.length);
}
public int GetHashCode(RangeInt obj)
{
return obj.start.GetHashCode() ^ obj.length.GetHashCode() << 2;
}
}
sealed class RectIntEqualityComparer : IEqualityComparer<RectInt>
{
public bool Equals(RectInt self, RectInt other)
{
return self.x.Equals(other.x) && self.width.Equals(other.width) && self.y.Equals(other.y) && self.height.Equals(other.height);
}
public int GetHashCode(RectInt obj)
{
return obj.x.GetHashCode() ^ obj.width.GetHashCode() << 2 ^ obj.y.GetHashCode() >> 2 ^ obj.height.GetHashCode() >> 1;
}
}
sealed class BoundsIntEqualityComparer : IEqualityComparer<BoundsInt>
{
public bool Equals(BoundsInt self, BoundsInt vector)
{
return Vector3IntEqualityComparer.Default.Equals(self.position, vector.position)
&& Vector3IntEqualityComparer.Default.Equals(self.size, vector.size);
}
public int GetHashCode(BoundsInt obj)
{
return Vector3IntEqualityComparer.Default.GetHashCode(obj.position) ^ Vector3IntEqualityComparer.Default.GetHashCode(obj.size) << 2;
}
}
#endif
}
}

View File

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

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine.Networking;
namespace Cysharp.Threading.Tasks.Internal
{
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
internal static class UnityWebRequestResultExtensions
{
public static bool IsError(this UnityWebRequest unityWebRequest)
{
#if UNITY_2020_2_OR_NEWER
var result = unityWebRequest.result;
return (result == UnityWebRequest.Result.ConnectionError)
|| (result == UnityWebRequest.Result.DataProcessingError)
|| (result == UnityWebRequest.Result.ProtocolError);
#else
return unityWebRequest.isHttpError || unityWebRequest.isNetworkError;
#endif
}
}
#endif
}

View File

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

Some files were not shown because too many files have changed in this diff Show More