diff --git a/UniTask.NetCore.sln b/UniTask.NetCore.sln
index 46cbf3e..aa5abe9 100644
--- a/UniTask.NetCore.sln
+++ b/UniTask.NetCore.sln
@@ -1,13 +1,15 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29613.14
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31606.5
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCore", "src\UniTask.NetCore\UniTask.NetCore.csproj", "{16EE20D0-7FB1-483A-8467-A5EEDBF1F5BF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.Analyzer", "src\UniTask.Analyzer\UniTask.Analyzer.csproj", "{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,6 +29,10 @@ Global
{3915E72E-33E0-4A14-A6D8-872702200E58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/UniTask.Analyzer/Properties/launchSettings.json b/src/UniTask.Analyzer/Properties/launchSettings.json
new file mode 100644
index 0000000..9742dc6
--- /dev/null
+++ b/src/UniTask.Analyzer/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "UniTask.Analyzer": {
+ "commandName": "DebugRoslynComponent",
+ "targetProject": "..\\UniTask.NetCoreSandbox\\UniTask.NetCoreSandbox.csproj"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UniTask.Analyzer/UniTask.Analyzer.csproj b/src/UniTask.Analyzer/UniTask.Analyzer.csproj
new file mode 100644
index 0000000..0c1b6d3
--- /dev/null
+++ b/src/UniTask.Analyzer/UniTask.Analyzer.csproj
@@ -0,0 +1,29 @@
+
+
+ library
+ netstandard2.0
+ latest
+ enable
+ true
+ $(TargetsForTfmSpecificContentInPackage);PackBuildOutputs
+ false
+ false
+ true
+ true
+
+
+
+
+ runtime; build; native; contentfiles; analyzers
+ all
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UniTask.Analyzer/UniTaskAnalyzer.cs b/src/UniTask.Analyzer/UniTaskAnalyzer.cs
new file mode 100644
index 0000000..3d28035
--- /dev/null
+++ b/src/UniTask.Analyzer/UniTaskAnalyzer.cs
@@ -0,0 +1,54 @@
+#pragma warning disable RS2008
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+using System.Collections.Immutable;
+using System.Threading;
+
+namespace UniTask.Analyzer
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class UniTaskAnalyzer : DiagnosticAnalyzer
+ {
+ private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
+ id: "UNITASK001",
+ title: "UniTaskAnalyzer001: Must pass CancellationToken",
+ messageFormat: "Must pass CancellationToken",
+ category: "Usage",
+ defaultSeverity: DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: "Pass CancellationToken or CancellationToken.None.");
+
+ public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ context.RegisterOperationAction(AnalyzeSymbol, OperationKind.Invocation);
+ }
+
+ private static void AnalyzeSymbol(OperationAnalysisContext context)
+ {
+ var token = context.Compilation.GetTypeByMetadataName(typeof(CancellationToken).FullName);
+ if (token == null) return;
+
+ if (context.Operation is IInvocationOperation invocation)
+ {
+ foreach (var arg in invocation.Arguments)
+ {
+ if (arg.ArgumentKind == ArgumentKind.DefaultValue)
+ {
+ if (SymbolEqualityComparer.Default.Equals(arg.Parameter.Type, token))
+ {
+ var diagnostic = Diagnostic.Create(Rule, arg.Syntax.GetLocation());
+ context.ReportDiagnostic(diagnostic);
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UniTask.NetCoreSandbox/AllocationCheck.cs b/src/UniTask.NetCoreSandbox/AllocationCheck.cs
deleted file mode 100644
index 1efecb3..0000000
--- a/src/UniTask.NetCoreSandbox/AllocationCheck.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using System.Linq;
-using BenchmarkDotNet.Configs;
-using BenchmarkDotNet.Diagnosers;
-using BenchmarkDotNet.Exporters;
-using BenchmarkDotNet.Jobs;
-using BenchmarkDotNet.Running;
-using Cysharp.Threading.Tasks;
-using PooledAwait;
-using System;
-using System.Runtime.ExceptionServices;
-using System.Threading.Tasks;
-using System.Threading;
-using System.Runtime.CompilerServices;
-using Cysharp.Threading.Tasks.CompilerServices;
-using System.Collections.Concurrent;
-
-[Config(typeof(BenchmarkConfig))]
-public class AllocationCheck
-{
- // note: all the benchmarks use Task/Task for the public API, because BenchmarkDotNet
- // doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
- // we'll obscure the cost of the outer awaitable by doing a relatively large number of
- // iterations, so that we're only really measuring the inner loop
- private const int InnerOps = 1000;
-
- [Benchmark(OperationsPerInvoke = InnerOps)]
- public async Task ViaUniTask()
- {
- for (int i = 0; i < InnerOps; i++)
- {
- var a = Core();
- var b = Core();
- var c = Core();
- await a;
- await b;
- await c;
- }
-
- static async UniTask Core()
- {
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps)]
- public async Task ViaUniTaskT()
- {
- var sum = 0;
- for (int i = 0; i < InnerOps; i++)
- {
- var a = Core();
- var b = Core();
- var c = Core();
- sum += await a;
- sum += await b;
- sum += await c;
- }
- return sum;
-
- static async UniTask Core()
- {
- var a = await new TestAwaiter(false, UniTaskStatus.Succeeded, 10);
- var b = await new TestAwaiter(false, UniTaskStatus.Succeeded, 10);
- var c = await new TestAwaiter(false, UniTaskStatus.Succeeded, 10);
- return 10;
- }
- }
-
- //[Benchmark(OperationsPerInvoke = InnerOps)]
- //[Benchmark]
- public void ViaUniTaskVoid()
- {
- for (int i = 0; i < InnerOps; i++)
- {
- Core().Forget();
- Core().Forget();
- Core().Forget();
- }
-
- static async UniTaskVoid Core()
- {
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- }
- }
-
- struct Foo : IAsyncStateMachine
- {
- public AsyncUniTaskVoidMethodBuilder builder;
- public TestAwaiter awaiter;
- public TestAwaiter awaiterawaiter;
-
- public int state;
-
- public void MoveNext()
- {
- switch (state)
- {
- case -1:
- awaiterawaiter = awaiter.GetAwaiter();
- if (awaiterawaiter.IsCompleted)
- {
- goto case 0;
- }
- else
- {
- state = 0;
- builder.AwaitUnsafeOnCompleted(ref awaiterawaiter, ref this);
- return;
- }
-
- case 0:
- default:
- goto END;
- }
-
- END:
- builder.SetResult();
- }
-
- public void SetStateMachine(IAsyncStateMachine stateMachine)
- {
-
- }
- }
-}
-
-public class TaskTestException : Exception
-{
-
-}
-
-public struct TestAwaiter : ICriticalNotifyCompletion
-{
- readonly UniTaskStatus status;
- readonly bool isCompleted;
-
- public TestAwaiter(bool isCompleted, UniTaskStatus status)
- {
- this.isCompleted = isCompleted;
- this.status = status;
- }
-
- public TestAwaiter GetAwaiter() => this;
-
- public bool IsCompleted => isCompleted;
-
- public void GetResult()
- {
- switch (status)
- {
- case UniTaskStatus.Faulted:
- throw new TaskTestException();
- case UniTaskStatus.Canceled:
- throw new OperationCanceledException();
- case UniTaskStatus.Pending:
- case UniTaskStatus.Succeeded:
- default:
- break;
- }
- }
-
- public void OnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
- }
-
- public void UnsafeOnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
- }
-
-
-}
-
-public struct TestAwaiter : ICriticalNotifyCompletion
-{
- readonly UniTaskStatus status;
- readonly bool isCompleted;
- readonly T value;
-
- public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
- {
- this.isCompleted = isCompleted;
- this.status = status;
- this.value = value;
- }
-
- public TestAwaiter GetAwaiter() => this;
-
- public bool IsCompleted => isCompleted;
-
- public T GetResult()
- {
- switch (status)
- {
- case UniTaskStatus.Faulted:
- throw new TaskTestException();
- case UniTaskStatus.Canceled:
- throw new OperationCanceledException();
- case UniTaskStatus.Pending:
- case UniTaskStatus.Succeeded:
- default:
- return value;
- }
- }
-
- public void OnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
- }
-
- public void UnsafeOnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
- }
-}
-
-public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
-{
- public static readonly ConcurrentQueue pool = new ConcurrentQueue();
-
- public static void CreatePoolItems(int count)
- {
- for (int i = 0; i < count; i++)
- {
- pool.Enqueue(new ThreadPoolWorkItem());
- }
- }
-
- Action continuation;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ThreadPoolWorkItem Create(Action continuation)
- {
- if (!pool.TryDequeue(out var item))
- {
- item = new ThreadPoolWorkItem();
- }
-
- item.continuation = continuation;
- return item;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Execute()
- {
- var call = continuation;
- continuation = null;
- pool.Enqueue(this);
-
- call.Invoke();
- }
-}
\ No newline at end of file
diff --git a/src/UniTask.NetCoreSandbox/Benchmark.cs b/src/UniTask.NetCoreSandbox/Benchmark.cs
deleted file mode 100644
index 94a2ca7..0000000
--- a/src/UniTask.NetCoreSandbox/Benchmark.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using System.Linq;
-using BenchmarkDotNet.Configs;
-using BenchmarkDotNet.Diagnosers;
-using BenchmarkDotNet.Exporters;
-using BenchmarkDotNet.Jobs;
-using BenchmarkDotNet.Running;
-using Cysharp.Threading.Tasks;
-using PooledAwait;
-using System;
-using System.Runtime.ExceptionServices;
-using System.Threading.Tasks;
-using System.Threading;
-using System.Runtime.CompilerServices;
-using Cysharp.Threading.Tasks.CompilerServices;
-
-//class Program
-//{
-// static void Main(string[] args)
-// {
-// var switcher = new BenchmarkSwitcher(new[]
-// {
-// typeof(StandardBenchmark)
-// });
-
-//#if DEBUG
-// var b = new StandardBenchmark();
-
-//#else
-// switcher.Run(args);
-//#endif
-// }
-//}
-
-public class BenchmarkConfig : ManualConfig
-{
- public BenchmarkConfig()
- {
- AddDiagnoser(MemoryDiagnoser.Default);
- AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1)/*.RunOncePerIteration()*/);
- }
-}
-
-// borrowed from PooledAwait
-
-[Config(typeof(BenchmarkConfig))]
-[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
-[CategoriesColumn]
-public class ComparisonBenchmarks
-{
- // note: all the benchmarks use Task/Task for the public API, because BenchmarkDotNet
- // doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
- // we'll obscure the cost of the outer awaitable by doing a relatively large number of
- // iterations, so that we're only really measuring the inner loop
- private const int InnerOps = 1000;
-
- public bool ConfigureAwait { get; set; } = false;
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
- [BenchmarkCategory("Task")]
- public async Task ViaTaskT()
- {
- int sum = 0;
- for (int i = 0; i < InnerOps; i++)
- sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
- return sum;
-
- static async Task Inner(int x, int y)
- {
- int i = x;
- await Task.Yield();
- i *= y;
- await Task.Yield();
- return 5 * i;
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
- [BenchmarkCategory("Task")]
- public async Task ViaTask()
- {
- for (int i = 0; i < InnerOps; i++)
- await Inner().ConfigureAwait(ConfigureAwait);
-
- static async Task Inner()
- {
- await Task.Yield();
- await Task.Yield();
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
- [BenchmarkCategory("ValueTask")]
- public async Task ViaValueTaskT()
- {
- int sum = 0;
- for (int i = 0; i < InnerOps; i++)
- sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
- return sum;
-
- static async ValueTask Inner(int x, int y)
- {
- int i = x;
- await Task.Yield();
- i *= y;
- await Task.Yield();
- return 5 * i;
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
- [BenchmarkCategory("ValueTask")]
- public async Task ViaValueTask()
- {
- for (int i = 0; i < InnerOps; i++)
- await Inner().ConfigureAwait(ConfigureAwait);
-
- static async ValueTask Inner()
- {
- await Task.Yield();
- await Task.Yield();
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
- [BenchmarkCategory("ValueTask")]
- public async Task ViaPooledValueTaskT()
- {
- int sum = 0;
- for (int i = 0; i < InnerOps; i++)
- sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
- return sum;
-
- static async PooledValueTask Inner(int x, int y)
- {
- int i = x;
- await Task.Yield();
- i *= y;
- await Task.Yield();
- return 5 * i;
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
- [BenchmarkCategory("ValueTask")]
- public async Task ViaPooledValueTask()
- {
- for (int i = 0; i < InnerOps; i++)
- await Inner().ConfigureAwait(ConfigureAwait);
-
- static async PooledValueTask Inner()
- {
- await Task.Yield();
- await Task.Yield();
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
- [BenchmarkCategory("Task")]
- public async Task ViaPooledTaskT()
- {
- int sum = 0;
- for (int i = 0; i < InnerOps; i++)
- sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
- return sum;
-
- static async PooledTask Inner(int x, int y)
- {
- int i = x;
- await Task.Yield();
- i *= y;
- await Task.Yield();
- return 5 * i;
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
- [BenchmarkCategory("Task")]
- public async Task ViaPooledTask()
- {
- for (int i = 0; i < InnerOps; i++)
- await Inner().ConfigureAwait(ConfigureAwait);
-
- static async PooledTask Inner()
- {
- await Task.Yield();
- await Task.Yield();
- }
- }
-
- // ---
-
- //[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskVoid")]
- //[BenchmarkCategory("UniTask")]
- //public async Task ViaUniTaskVoid()
- //{
- // for (int i = 0; i < InnerOps; i++)
- // {
- // await Inner();
- // }
-
- // static async UniTaskVoid Inner()
- // {
- // await UniTask.Yield();
- // await UniTask.Yield();
- // }
- //}
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTask")]
- [BenchmarkCategory("UniTask")]
- public async Task ViaUniTask()
- {
- for (int i = 0; i < InnerOps; i++)
- {
- await Inner();
- }
-
- static async UniTask Inner()
- {
- await UniTask.Yield();
- await UniTask.Yield();
- }
- }
-
- [Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskT")]
- [BenchmarkCategory("UniTask")]
- public async Task ViaUniTaskT()
- {
- var sum = 0;
- for (int i = 0; i < InnerOps; i++)
- {
- sum += await Inner(1, 2);
- }
- return sum;
-
- static async UniTask Inner(int x, int y)
- {
- int i = x;
- await UniTask.Yield();
- i *= y;
- await UniTask.Yield();
- return 5 * i;
- }
- }
-}
-
-public struct MyAwaiter : ICriticalNotifyCompletion
-{
- public MyAwaiter GetAwaiter() => this;
-
- public bool IsCompleted => false;
-
- public void GetResult()
- {
- }
-
- public void OnCompleted(Action continuation)
- {
- continuation();
- }
-
- public void UnsafeOnCompleted(Action continuation)
- {
- continuation();
- }
-}
-
-public struct MyTestStateMachine : IAsyncStateMachine
-{
- public void MoveNext()
- {
- //throw new NotImplementedException();
-
-
-
-
- }
-
- public void SetStateMachine(IAsyncStateMachine stateMachine)
- {
- //throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/src/UniTask.NetCoreSandbox/Program.cs b/src/UniTask.NetCoreSandbox/Program.cs
index ad07bdf..8067ab7 100644
--- a/src/UniTask.NetCoreSandbox/Program.cs
+++ b/src/UniTask.NetCoreSandbox/Program.cs
@@ -17,499 +17,34 @@ using System.Reactive.Concurrency;
namespace NetCoreSandbox
{
- public class MySyncContext : SynchronizationContext
+ public class Program
{
- public MySyncContext()
- {
- }
-
- public override void Post(SendOrPostCallback d, object state)
- {
- Console.WriteLine("Called SyncContext Post!");
- base.Post(d, state);
- }
- }
-
- public class Text
- {
-
- public string text { get; set; }
- }
-
- public class ZeroAllocAsyncAwaitInDotNetCore
- {
- public ValueTask NanikaAsync(int x, int y)
- {
- return Core(this, x, y);
-
- static async UniTask Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
- {
- // nanika suru...
- await Task.Delay(TimeSpan.FromSeconds(x + y));
-
- return 10;
- }
- }
- }
-
-
- public class TaskTestException : Exception
- {
-
- }
-
- class Foo
- {
- public async UniTask MethodFooAsync()
- {
- await MethodBarAsync();
- }
-
- private async UniTask MethodBarAsync()
-
- {
- Throw();
- }
-
- private void Throw()
- {
- throw new Exception();
- }
- }
-
- public struct TestAwaiter : ICriticalNotifyCompletion
- {
- readonly UniTaskStatus status;
- readonly bool isCompleted;
-
- public TestAwaiter(bool isCompleted, UniTaskStatus status)
- {
- this.isCompleted = isCompleted;
- this.status = status;
- }
-
- public TestAwaiter GetAwaiter() => this;
-
- public bool IsCompleted => isCompleted;
-
- public void GetResult()
- {
- switch (status)
- {
- case UniTaskStatus.Faulted:
- throw new TaskTestException();
- case UniTaskStatus.Canceled:
- throw new OperationCanceledException();
- case UniTaskStatus.Pending:
- case UniTaskStatus.Succeeded:
- default:
- break;
- }
- }
-
- public void OnCompleted(Action continuation)
- {
- ThreadPool.QueueUserWorkItem(_ => continuation(), null);
- }
-
- public void UnsafeOnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
- }
- }
- public struct TestAwaiter : ICriticalNotifyCompletion
- {
- readonly UniTaskStatus status;
- readonly bool isCompleted;
- readonly T value;
-
- public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
- {
- this.isCompleted = isCompleted;
- this.status = status;
- this.value = value;
- }
-
- public TestAwaiter GetAwaiter() => this;
-
- public bool IsCompleted => isCompleted;
-
- public T GetResult()
- {
- switch (status)
- {
- case UniTaskStatus.Faulted:
- throw new TaskTestException();
- case UniTaskStatus.Canceled:
- throw new OperationCanceledException();
- case UniTaskStatus.Pending:
- case UniTaskStatus.Succeeded:
- default:
- return value;
- }
- }
-
- public void OnCompleted(Action continuation)
- {
- ThreadPool.QueueUserWorkItem(_ => continuation(), null);
- }
-
- public void UnsafeOnCompleted(Action continuation)
- {
- ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
- }
- }
-
-
- public static partial class UnityUIComponentExtensions
- {
- public static void BindTo(this IUniTaskAsyncEnumerable source, Text text)
- {
- AAAACORECORE(source, text).Forget();
-
- async UniTaskVoid AAAACORECORE(IUniTaskAsyncEnumerable source2, Text text2)
- {
- var e = source2.GetAsyncEnumerator();
- try
- {
- while (await e.MoveNextAsync())
- {
- text2.text = e.Current;
- // action(e.Current);
- }
- }
- finally
- {
- if (e != null)
- {
- await e.DisposeAsync();
- }
- }
- }
- }
-
- //public static IDisposable SubscribeToText(this IObservable source, Text text)
- //{
- // return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
- //}
-
- //public static IDisposable SubscribeToText(this IObservable source, Text text, Func selector)
- //{
- // return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
- //}
-
- //public static IDisposable SubscribeToInteractable(this IObservable source, Selectable selectable)
- //{
- // return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
- //}
- }
-
- class Program
- {
- static string FlattenGenArgs(Type type)
- {
- if (type.IsGenericType)
- {
- var t = string.Join(", ", type.GetGenericArguments().Select(x => FlattenGenArgs(x)));
- return Regex.Replace(type.Name, "`.+", "") + "<" + t + ">";
- }
- //x.ReturnType.GetGenericArguments()
- else
- {
- return type.Name;
- }
- }
-
- static async IAsyncEnumerable FooAsync([EnumeratorCancellation]CancellationToken cancellationToken = default)
- {
- yield return 1;
- await Task.Delay(10, cancellationToken);
- }
-
- public class MyDisposable : IDisposable
- {
- public void Dispose()
- {
-
- }
- }
-
- static void Test()
- {
- var disp = new MyDisposable();
-
- using var _ = new MyDisposable();
-
- Console.WriteLine("tako");
- }
-
-
- static async UniTask FooBarAsync()
- {
- await using (UniTask.ReturnToCurrentSynchronizationContext())
- {
- await UniTask.SwitchToThreadPool();
-
-
-
-
- }
- }
-
-
-
-
- static async UniTask Aaa()
- {
- await FooBarAsync();
-
- Console.WriteLine("FooBarAsync End");
- }
-
- static async UniTask WhereSelect()
- {
- await foreach (var item in UniTaskAsyncEnumerable.Range(1, 10)
- .SelectAwait(async x =>
- {
- await UniTask.Yield();
- return x;
- })
- .Where(x => x % 2 == 0))
- {
- Console.WriteLine(item);
- }
- }
-
-
static async Task Main(string[] args)
{
-#if !DEBUG
-
+ var cts = new CancellationTokenSource();
+
+
+ // OK.
+ await FooAsync(10, cts.Token);
+
+ // NG(Compiler Error)
+ await FooAsync(10);
+
+
+
- //await new AllocationCheck().ViaUniTaskVoid();
- //Console.ReadLine();
- BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
- //await new ComparisonBenchmarks().ViaUniTaskT();
- return;
-#endif
-
- var e = UniTaskAsyncEnumerable.Create(async (writer, token) =>
- {
- for (int i = 0; i < 5; i++)
- {
- Console.WriteLine($"Start {i}");
- await writer.YieldAsync(i);
- Console.WriteLine($"End {i}");
- }
- });
-
- var ee = e.GetAsyncEnumerator();
- while (await ee.MoveNextAsync())
- {
- Console.WriteLine("ForEach " + ee.Current);
- }
}
- static async UniTask YieldCore()
+ static async UniTask FooAsync(int x, CancellationToken cancellationToken = default)
{
await UniTask.Yield();
}
-
-#pragma warning disable CS1998
-
-
- static async UniTask AsyncTest()
- {
- // empty
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- await new TestAwaiter(true, UniTaskStatus.Succeeded);
- await new TestAwaiter(false, UniTaskStatus.Succeeded);
- return 10;
- }
-
-
-
-#pragma warning restore CS1998
-
- void Foo()
- {
-
- // AsyncEnumerable.Range(1,10).Do(
-
- // AsyncEnumerable.t
-
- var sb = new StringBuilder();
- sb.AppendLine(@"using System;
-using System.Threading;
-
-namespace Cysharp.Threading.Tasks.Linq
-{
-");
-
-
-
- var chako = typeof(AsyncEnumerable).GetMethods()
- .OrderBy(x => x.Name)
- .Select(x =>
- {
- var ret = FlattenGenArgs(x.ReturnType);
-
-
- var generics = string.Join(", ", x.GetGenericArguments().Select(x => x.Name));
-
- if (x.GetParameters().Length == 0) return "";
-
- var self = x.GetParameters().First();
- if (x.GetCustomAttributes(typeof(ExtensionAttribute), true).Length == 0)
- {
- return "";
- }
-
- var arg1Type = FlattenGenArgs(x.GetParameters().First().ParameterType);
-
- var others = string.Join(", ", x.GetParameters().Skip(1).Select(y => FlattenGenArgs(y.ParameterType) + " " + y.Name));
-
- if (!string.IsNullOrEmpty(others))
- {
- others = ", " + others;
- }
-
- var template = $"public static {ret} {x.Name}<{generics}>(this {arg1Type} {self.Name}{others})";
-
-
-
- return template.Replace("ValueTask", "UniTask").Replace("IAsyncEnumerable", "IUniTaskAsyncEnumerable").Replace("<>", "");
- })
- .Where(x => x != "")
- .Select(x => x + "\r\n{\r\n throw new NotImplementedException();\r\n}")
- .ToArray();
-
- var huga = string.Join("\r\n\r\n", chako);
-
-
-
-
- foreach (var item in typeof(AsyncEnumerable).GetMethods().Select(x => x.Name).Distinct())
- {
- if (item.EndsWith("AwaitAsync") || item.EndsWith("AwaitWithCancellationAsync") || item.EndsWith("WithCancellation"))
- {
- continue;
- }
-
- var item2 = item.Replace("Async", "");
- item2 = item2.Replace("Await", "");
-
- var format = @"
- internal sealed class {0}
- {{
- }}
-";
-
- sb.Append(string.Format(format, item2));
-
- }
-
- sb.Append("}");
-
-
- Console.WriteLine(sb.ToString());
-
-
-
-
- }
-
-
- public static async IAsyncEnumerable AsyncGen()
- {
- await UniTask.SwitchToThreadPool();
- yield return 10;
- await UniTask.SwitchToThreadPool();
- yield return 100;
- }
}
- class MyEnumerable : IEnumerable
- {
- public IEnumerator GetEnumerator()
- {
- return new MyEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- throw new NotImplementedException();
- }
- }
-
- class MyEnumerator : IEnumerator
- {
- public int Current => throw new NotImplementedException();
-
- object IEnumerator.Current => throw new NotImplementedException();
-
- public void Dispose()
- {
- Console.WriteLine("Called Dispose");
- }
-
- public bool MoveNext()
- {
- throw new NotImplementedException();
- }
-
- public void Reset()
- {
- throw new NotImplementedException();
- }
- }
-
-
-
- public class MyClass
- {
- public CustomAsyncEnumerator GetAsyncEnumerator()
- {
- //IAsyncEnumerable
- return new CustomAsyncEnumerator();
- }
- }
-
-
- public struct CustomAsyncEnumerator
- {
- int count;
-
- public T Current
- {
- get
- {
- return default;
- }
- }
-
- public UniTask MoveNextAsync()
- {
- if (count++ == 3)
- {
- return UniTask.FromResult(false);
- //return false;
- }
- return UniTask.FromResult(true);
- }
-
- public UniTask DisposeAsync()
- {
- return default;
- }
- }
-
-
-
}
diff --git a/src/UniTask.NetCoreSandbox/QueueCheck.cs b/src/UniTask.NetCoreSandbox/QueueCheck.cs
deleted file mode 100644
index 3e0937c..0000000
--- a/src/UniTask.NetCoreSandbox/QueueCheck.cs
+++ /dev/null
@@ -1,473 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-[Config(typeof(BenchmarkConfig))]
-public class QueueCheck
-{
- Node node1 = new Node();
- Node node2 = new Node();
- RefNode refNode1 = new RefNode();
- RefNode refNode2 = new RefNode();
- Queue q1 = new Queue();
- Stack s1 = new Stack();
- ConcurrentQueue cq = new ConcurrentQueue();
- ConcurrentStack cs = new ConcurrentStack();
- static TaskPool pool;
- static TaskPoolRefNode poolRefNode;
- static TaskPoolEqualNull poolEqualNull;
- static TaskPoolClass poolClass = new TaskPoolClass();
- static TaskPoolWithoutSize poolWithoutSize;
- static TaskPoolWithoutLock poolWithoutLock;
-
- [Benchmark]
- public void Queue()
- {
- q1.Enqueue(node1);
- q1.Enqueue(node1);
- q1.TryDequeue(out _);
- q1.TryDequeue(out _);
- }
-
- [Benchmark]
- public void QueueLock()
- {
- lock (q1) { q1.Enqueue(node1); }
- lock (q1) { q1.Enqueue(node1); }
- lock (q1) { q1.TryDequeue(out _); }
- lock (q1) { q1.TryDequeue(out _); }
- }
-
- [Benchmark]
- public void Stack()
- {
- s1.Push(node1);
- s1.Push(node2);
- s1.TryPop(out _);
- s1.TryPop(out _);
- }
-
- [Benchmark]
- public void StackLock()
- {
- lock (s1) { s1.Push(node1); }
- lock (s1) { s1.Push(node2); }
- lock (s1) { s1.TryPop(out _); }
- lock (s1) { s1.TryPop(out _); }
- }
-
- [Benchmark]
- public void ConcurrentQueue()
- {
- cq.Enqueue(node1);
- cq.Enqueue(node1);
- cq.TryDequeue(out _);
- cq.TryDequeue(out _);
- }
-
- [Benchmark]
- public void ConcurrentStack()
- {
- cs.Push(node1);
- cs.Push(node2);
- cs.TryPop(out _);
- cs.TryPop(out _);
- }
-
- [Benchmark]
- public void TaskPool()
- {
- pool.TryPush(node1);
- pool.TryPush(node2);
- pool.TryPop(out _);
- pool.TryPop(out _);
- }
- [Benchmark]
- public void TaskPoolRefNode()
- {
- poolRefNode.TryPush(refNode1);
- poolRefNode.TryPush(refNode2);
- poolRefNode.TryPop(out _);
- poolRefNode.TryPop(out _);
- }
-
- [Benchmark]
- public void TaskPoolEqualNull()
- {
- poolEqualNull.TryPush(node1);
- poolEqualNull.TryPush(node2);
- poolEqualNull.TryPop(out _);
- poolEqualNull.TryPop(out _);
- }
-
- [Benchmark]
- public void TaskPoolClass()
- {
- poolClass.TryPush(node1);
- poolClass.TryPush(node2);
- poolClass.TryPop(out _);
- poolClass.TryPop(out _);
- }
-
- [Benchmark]
- public void TaskPoolWithoutSize()
- {
- poolWithoutSize.TryPush(node1);
- poolWithoutSize.TryPush(node2);
- poolWithoutSize.TryPop(out _);
- poolWithoutSize.TryPop(out _);
- }
-
- [Benchmark]
- public void TaskPoolWithoutLock()
- {
- poolWithoutLock.TryPush(node1);
- poolWithoutLock.TryPush(node2);
- poolWithoutLock.TryPop(out _);
- poolWithoutLock.TryPop(out _);
- }
-}
-
-public sealed class Node : ITaskPoolNode
-{
- public Node NextNode { get; set; }
-}
-
-public interface ITaskPoolNode
-{
- T NextNode { get; set; }
-}
-
-public sealed class RefNode :ITaskPoolRefNode
-{
- RefNode nextNode;
- public ref RefNode NextNode => ref nextNode;
-}
-
-public interface ITaskPoolRefNode
-{
- ref T NextNode { get; }
-}
-
-
-// mutable struct, don't mark readonly.
-[StructLayout(LayoutKind.Auto)]
-public struct TaskPoolWithoutLock
- where T : class, ITaskPoolNode
-{
- int size;
- T root;
-
- public int Size => size;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- //if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (!(v is null))
- {
- root = v.NextNode;
- v.NextNode = null;
- size--;
- result = v;
- // Volatile.Write(ref gate, 0);
- return true;
- }
-
- //Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- //if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- size++;
- // Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- //return false;
- }
-}
-
-[StructLayout(LayoutKind.Auto)]
-public struct TaskPool
- where T : class, ITaskPoolNode
-{
- int gate;
- int size;
- T root;
-
- public int Size => size;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (!(v is null))
- {
- root = v.NextNode;
- v.NextNode = null;
- size--;
- result = v;
- Volatile.Write(ref gate, 0);
- return true;
- }
-
- Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- size++;
- Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- return false;
- }
-}
-[StructLayout(LayoutKind.Auto)]
-public struct TaskPoolRefNode
- where T : class, ITaskPoolRefNode
-{
- int gate;
- int size;
- T root;
-
- public int Size => size;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (!(v is null))
- {
- ref var nextNode = ref v.NextNode;
- root = nextNode;
- nextNode = null;
- size--;
- result = v;
- Volatile.Write(ref gate, 0);
- return true;
- }
-
- Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- size++;
- Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- return false;
- }
-}
-
-[StructLayout(LayoutKind.Auto)]
-public struct TaskPoolEqualNull
- where T : class, ITaskPoolNode
-{
- int gate;
- int size;
- T root;
-
- public int Size => size;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (v != null)
- {
- root = v.NextNode;
- v.NextNode = null;
- size--;
- result = v;
- Volatile.Write(ref gate, 0);
- return true;
- }
-
- Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- size++;
- Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- return false;
- }
-}
-
-public class TaskPoolClass
- where T : class, ITaskPoolNode
-{
- int gate;
- int size;
- T root;
-
- public int Size => size;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (!(v is null))
- {
- root = v.NextNode;
- v.NextNode = null;
- size--;
- result = v;
- Volatile.Write(ref gate, 0);
- return true;
- }
-
- Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- size++;
- Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- return false;
- }
-}
-
-[StructLayout(LayoutKind.Auto)]
-public struct TaskPoolWithoutSize
- where T : class, ITaskPoolNode
-{
- int gate;
- T root;
-
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPop(out T result)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- var v = root;
- if (!(v is null))
- {
- root = v.NextNode;
- v.NextNode = null;
- result = v;
- Volatile.Write(ref gate, 0);
- return true;
- }
-
- Volatile.Write(ref gate, 0);
- }
- result = default;
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryPush(T item)
- {
- if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
- {
- //if (size < TaskPool.MaxPoolSize)
- {
- item.NextNode = root;
- root = item;
- Volatile.Write(ref gate, 0);
- return true;
- }
- //else
- {
- // Volatile.Write(ref gate, 0);
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/UniTask.NetCoreSandbox/UniTask.NetCoreSandbox.csproj b/src/UniTask.NetCoreSandbox/UniTask.NetCoreSandbox.csproj
index 6d531d0..cc33684 100644
--- a/src/UniTask.NetCoreSandbox/UniTask.NetCoreSandbox.csproj
+++ b/src/UniTask.NetCoreSandbox/UniTask.NetCoreSandbox.csproj
@@ -15,6 +15,12 @@
+
+
+
+ false
+ Analyzer
+