From 51ba7404132807d04a85bb764f2fac6e47795144 Mon Sep 17 00:00:00 2001 From: neuecc Date: Sun, 24 May 2020 00:18:39 +0900 Subject: [PATCH] In .NET Core, IUniTaskSource implements IValueTaskSource and implicit, zero overhead conversion --- .../NetCore/UniTask.AsValueTask.cs | 112 +----------------- src/UniTask.NetCore/UniTask.NetCore.csproj | 3 +- src/UniTask.NetCoreSandbox/Program.cs | 25 +++- .../Plugins/UniTask/Runtime/IUniTaskSource.cs | 58 +++++++++ .../Assets/Plugins/UniTask/Runtime/UniTask.cs | 28 +++++ 5 files changed, 115 insertions(+), 111 deletions(-) diff --git a/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs b/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs index 834968a..e780c62 100644 --- a/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs +++ b/src/UniTask.NetCore/NetCore/UniTask.AsValueTask.cs @@ -1,123 +1,19 @@ #pragma warning disable 0649 -using System; -using System.Runtime.CompilerServices; using System.Threading.Tasks; -using System.Threading.Tasks.Sources; namespace Cysharp.Threading.Tasks { public static class UniTaskValueTaskExtensions { - public static ValueTask AsValueTask(this UniTask task) + public static ValueTask AsValueTask(this in UniTask task) { - ref var core = ref Unsafe.As(ref task); - if (core.source == null) - { - return default; - } - - return new ValueTask(new UniTaskValueTaskSource(core.source), core.token); + return task; } - public static ValueTask AsValueTask(this UniTask task) + public static ValueTask AsValueTask(this in UniTask task) { - ref var core = ref Unsafe.As, UniTaskToValueTask>(ref task); - if (core.source == null) - { - return new ValueTask(core.result); - } - - return new ValueTask(new UniTaskValueTaskSource(core.source), core.token); - } - - struct UniTaskToValueTask - { - public IUniTaskSource source; - public short token; - } - - class UniTaskValueTaskSource : IValueTaskSource - { - readonly IUniTaskSource source; - - public UniTaskValueTaskSource(IUniTaskSource source) - { - this.source = source; - } - - public void GetResult(short token) - { - source.GetResult(token); - } - - public ValueTaskSourceStatus GetStatus(short token) - { - var status = source.GetStatus(token); - switch (status) - { - case UniTaskStatus.Pending: - return ValueTaskSourceStatus.Pending; - case UniTaskStatus.Succeeded: - return ValueTaskSourceStatus.Succeeded; - case UniTaskStatus.Faulted: - return ValueTaskSourceStatus.Faulted; - case UniTaskStatus.Canceled: - return ValueTaskSourceStatus.Canceled; - default: - return (ValueTaskSourceStatus)status; - } - } - - public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) - { - source.OnCompleted(continuation, state, token); - } - } - - struct UniTaskToValueTask - { - public IUniTaskSource source; - public T result; - public short token; - } - - class UniTaskValueTaskSource : IValueTaskSource - { - readonly IUniTaskSource source; - - public UniTaskValueTaskSource(IUniTaskSource source) - { - this.source = source; - } - - public T GetResult(short token) - { - return source.GetResult(token); - } - - public ValueTaskSourceStatus GetStatus(short token) - { - var status = source.GetStatus(token); - switch (status) - { - case UniTaskStatus.Pending: - return ValueTaskSourceStatus.Pending; - case UniTaskStatus.Succeeded: - return ValueTaskSourceStatus.Succeeded; - case UniTaskStatus.Faulted: - return ValueTaskSourceStatus.Faulted; - case UniTaskStatus.Canceled: - return ValueTaskSourceStatus.Canceled; - default: - return (ValueTaskSourceStatus)status; - } - } - - public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) - { - source.OnCompleted(continuation, state, token); - } + return task; } } } diff --git a/src/UniTask.NetCore/UniTask.NetCore.csproj b/src/UniTask.NetCore/UniTask.NetCore.csproj index 23b0cda..6a9b15d 100644 --- a/src/UniTask.NetCore/UniTask.NetCore.csproj +++ b/src/UniTask.NetCore/UniTask.NetCore.csproj @@ -1,8 +1,9 @@  - netstandard2.0 + netstandard2.1 UniTask + 8.0 Cysharp.Threading.Tasks diff --git a/src/UniTask.NetCoreSandbox/Program.cs b/src/UniTask.NetCoreSandbox/Program.cs index 32de3a0..ee1989e 100644 --- a/src/UniTask.NetCoreSandbox/Program.cs +++ b/src/UniTask.NetCoreSandbox/Program.cs @@ -21,6 +21,25 @@ namespace NetCoreSandbox 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 static partial class UnityUIComponentExtensions { public static void BindTo(this IUniTaskAsyncEnumerable source, Text text) @@ -88,8 +107,10 @@ namespace NetCoreSandbox - static void Main(string[] args) + static async Task Main(string[] args) { + var foo = await new ZeroAllocAsyncAwaitInDotNetCore().NanikaAsync(1, 2); + Console.WriteLine(foo); var channel = Channel.CreateSingleConsumerUnbounded(); @@ -99,7 +120,7 @@ namespace NetCoreSandbox var token = cts.Token; - FooAsync(token).ForEachAsync(x => { }, token); + await FooAsync(token).ForEachAsync(x => { }, token); // Observable.Range(1,10).CombineLatest( diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/IUniTaskSource.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/IUniTaskSource.cs index 6b7e26c..4904d14 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/IUniTaskSource.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/IUniTaskSource.cs @@ -19,17 +19,75 @@ namespace Cysharp.Threading.Tasks // similar as IValueTaskSource public interface IUniTaskSource +#if !UNITY_2018_3_OR_NEWER + : System.Threading.Tasks.Sources.IValueTaskSource +#pragma warning disable CS0108 +#endif { UniTaskStatus GetStatus(short token); void OnCompleted(Action continuation, object state, short token); void GetResult(short token); UniTaskStatus UnsafeGetStatus(); // only for debug use. + +#if !UNITY_2018_3_OR_NEWER +#pragma warning restore CS0108 + + 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 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 : IUniTaskSource +#if !UNITY_2018_3_OR_NEWER + , System.Threading.Tasks.Sources.IValueTaskSource +#endif { new T GetResult(short token); + +#if !UNITY_2018_3_OR_NEWER + + new public UniTaskStatus GetStatus(short token) + { + return ((IUniTaskSource)this).GetStatus(token); + } + + new public void OnCompleted(Action continuation, object state, short token) + { + ((IUniTaskSource)this).OnCompleted(continuation, state, token); + } + + System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token) + { + return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token); + } + + T System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token) + { + return ((IUniTaskSource)this).GetResult(token); + } + + void System.Threading.Tasks.Sources.IValueTaskSource.OnCompleted(Action 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 diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.cs index 35bf8b6..36d5b6e 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.cs @@ -68,6 +68,20 @@ namespace Cysharp.Threading.Tasks return new UniTask(new IsCanceledSource(source), token); } +#if !UNITY_2018_3_OR_NEWER + + public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self) + { + if (self.source == null) + { + return default; + } + + return new System.Threading.Tasks.ValueTask(self.source, self.token); + } + +#endif + public override string ToString() { if (source == null) return "()"; @@ -414,6 +428,20 @@ namespace Cysharp.Threading.Tasks return self.AsUniTask(); } +#if !UNITY_2018_3_OR_NEWER + + public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self) + { + if (self.source == null) + { + return new System.Threading.Tasks.ValueTask(self.result); + } + + return new System.Threading.Tasks.ValueTask(self.source, self.token); + } + +#endif + /// /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException. ///