In .NET Core, IUniTaskSource implements IValueTaskSource and implicit, zero overhead conversion

pull/61/head
neuecc 2020-05-24 00:18:39 +09:00
parent f3e3ba8864
commit 51ba740413
5 changed files with 115 additions and 111 deletions

View File

@ -1,123 +1,19 @@
#pragma warning disable 0649 #pragma warning disable 0649
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace Cysharp.Threading.Tasks namespace Cysharp.Threading.Tasks
{ {
public static class UniTaskValueTaskExtensions 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<UniTask, UniTaskToValueTask>(ref task); return task;
if (core.source == null)
{
return default;
} }
return new ValueTask(new UniTaskValueTaskSource(core.source), core.token); public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
}
public static ValueTask<T> AsValueTask<T>(this UniTask<T> task)
{ {
ref var core = ref Unsafe.As<UniTask<T>, UniTaskToValueTask<T>>(ref task); return task;
if (core.source == null)
{
return new ValueTask<T>(core.result);
}
return new ValueTask<T>(new UniTaskValueTaskSource<T>(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<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
source.OnCompleted(continuation, state, token);
}
}
struct UniTaskToValueTask<T>
{
public IUniTaskSource<T> source;
public T result;
public short token;
}
class UniTaskValueTaskSource<T> : IValueTaskSource<T>
{
readonly IUniTaskSource<T> source;
public UniTaskValueTaskSource(IUniTaskSource<T> 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<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
source.OnCompleted(continuation, state, token);
}
} }
} }
} }

View File

@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<AssemblyName>UniTask</AssemblyName> <AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace> <RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
</PropertyGroup> </PropertyGroup>

View File

@ -21,6 +21,25 @@ namespace NetCoreSandbox
public string text { get; set; } public string text { get; set; }
} }
public class ZeroAllocAsyncAwaitInDotNetCore
{
public ValueTask<int> NanikaAsync(int x, int y)
{
return Core(this, x, y);
static async UniTask<int> Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
{
// nanika suru...
await Task.Delay(TimeSpan.FromSeconds(x + y));
return 10;
}
}
}
public static partial class UnityUIComponentExtensions public static partial class UnityUIComponentExtensions
{ {
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text) public static void BindTo(this IUniTaskAsyncEnumerable<string> 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<int>(); var channel = Channel.CreateSingleConsumerUnbounded<int>();
@ -99,7 +120,7 @@ namespace NetCoreSandbox
var token = cts.Token; var token = cts.Token;
FooAsync(token).ForEachAsync(x => { }, token); await FooAsync(token).ForEachAsync(x => { }, token);
// Observable.Range(1,10).CombineLatest( // Observable.Range(1,10).CombineLatest(

View File

@ -19,17 +19,75 @@ namespace Cysharp.Threading.Tasks
// similar as IValueTaskSource // similar as IValueTaskSource
public interface IUniTaskSource public interface IUniTaskSource
#if !UNITY_2018_3_OR_NEWER
: System.Threading.Tasks.Sources.IValueTaskSource
#pragma warning disable CS0108
#endif
{ {
UniTaskStatus GetStatus(short token); UniTaskStatus GetStatus(short token);
void OnCompleted(Action<object> continuation, object state, short token); void OnCompleted(Action<object> continuation, object state, short token);
void GetResult(short token); void GetResult(short token);
UniTaskStatus UnsafeGetStatus(); // only for debug use. 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<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 public interface IUniTaskSource<out T> : IUniTaskSource
#if !UNITY_2018_3_OR_NEWER
, System.Threading.Tasks.Sources.IValueTaskSource<T>
#endif
{ {
new T GetResult(short token); 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<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 public static class UniTaskStatusExtensions

View File

@ -68,6 +68,20 @@ namespace Cysharp.Threading.Tasks
return new UniTask<bool>(new IsCanceledSource(source), token); return new UniTask<bool>(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() public override string ToString()
{ {
if (source == null) return "()"; if (source == null) return "()";
@ -414,6 +428,20 @@ namespace Cysharp.Threading.Tasks
return self.AsUniTask(); return self.AsUniTask();
} }
#if !UNITY_2018_3_OR_NEWER
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
{
if (self.source == null)
{
return new System.Threading.Tasks.ValueTask<T>(self.result);
}
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
}
#endif
/// <summary> /// <summary>
/// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException. /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
/// </summary> /// </summary>