generator and tests

master
neuecc 2020-05-08 12:08:15 +09:00
parent 856a049dd0
commit ed0990e402
13 changed files with 1763 additions and 2586 deletions

View File

@ -1,775 +1,144 @@
namespace Cysharp.Threading.Tasks.Linq using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{ {
internal sealed class Count public static partial class UniTaskAsyncEnumerable
{ {
public static UniTask<Int32> CountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
return Count<TSource>.InvokeAsync(source, cancellationToken);
} }
public static UniTask<Int32> CountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(predicate, nameof(predicate));
return Count<TSource>.InvokeAsync(source, cancellationToken);
}
public static UniTask<Int32> CountAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(predicate, nameof(predicate));
return Count<TSource>.InvokeAsync(source, cancellationToken);
}
public static UniTask<Int32> CountAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(predicate, nameof(predicate));
return Count<TSource>.InvokeAsync(source, cancellationToken);
}
}
internal static class Count<TSource>
{
internal static async UniTask<int> InvokeAsync(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
{
var count = 0;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
checked { count++; }
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return count;
}
internal static async UniTask<int> InvokeAsync(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken)
{
var count = 0;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
if (predicate(e.Current))
{
checked { count++; }
}
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return count;
}
internal static async UniTask<int> InvokeAsync(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
{
var count = 0;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
if (await predicate(e.Current))
{
checked { count++; }
}
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return count;
}
internal static async UniTask<int> InvokeAsync(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
{
var count = 0;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
if (await predicate(e.Current, cancellationToken))
{
checked { count++; }
}
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return count;
}
}
} }

View File

@ -48,7 +48,7 @@ namespace Cysharp.Threading.Tasks.Linq
this.end = end; this.end = end;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.current = 0; this.current = start - 1;
} }
public int Current => current; public int Current => current;

View File

@ -5,39 +5,39 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
public static partial class UniTaskAsyncEnumerable public static partial class UniTaskAsyncEnumerable
{ {
public static IUniTaskAsyncEnumerable<TResult> Repeat<TResult>(TResult element, int count) public static IUniTaskAsyncEnumerable<TElement> Repeat<TElement>(TElement element, int count)
{ {
if (count < 0) throw Error.ArgumentOutOfRange(nameof(count)); if (count < 0) throw Error.ArgumentOutOfRange(nameof(count));
return new Repeat<TResult>(element, count); return new Repeat<TElement>(element, count);
} }
} }
internal class Repeat<TResult> : IUniTaskAsyncEnumerable<TResult> internal class Repeat<TElement> : IUniTaskAsyncEnumerable<TElement>
{ {
readonly TResult element; readonly TElement element;
readonly int count; readonly int count;
public Repeat(TResult element, int count) public Repeat(TElement element, int count)
{ {
this.element = element; this.element = element;
this.count = count; this.count = count;
} }
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
return new Enumerator(element, count, cancellationToken); return new Enumerator(element, count, cancellationToken);
} }
class Enumerator : IUniTaskAsyncEnumerator<TResult> class Enumerator : IUniTaskAsyncEnumerator<TElement>
{ {
readonly TResult element; readonly TElement element;
readonly int count; readonly int count;
int remaining; int remaining;
CancellationToken cancellationToken; CancellationToken cancellationToken;
public Enumerator(TResult element, int count, CancellationToken cancellationToken) public Enumerator(TElement element, int count, CancellationToken cancellationToken)
{ {
this.element = element; this.element = element;
this.count = count; this.count = count;
@ -46,7 +46,7 @@ namespace Cysharp.Threading.Tasks.Linq
this.remaining = count; this.remaining = count;
} }
public TResult Current => element; public TElement Current => element;
public UniTask<bool> MoveNextAsync() public UniTask<bool> MoveNextAsync()
{ {

View File

@ -0,0 +1,64 @@
using Cysharp.Threading.Tasks.Internal;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TValue> Return<TValue>(TValue value)
{
return new Return<TValue>(value);
}
}
internal class Return<TValue> : IUniTaskAsyncEnumerable<TValue>
{
readonly TValue value;
public Return(TValue value)
{
this.value = value;
}
public IUniTaskAsyncEnumerator<TValue> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return new Enumerator(value, cancellationToken);
}
class Enumerator : IUniTaskAsyncEnumerator<TValue>
{
readonly TValue value;
CancellationToken cancellationToken;
bool called;
public Enumerator(TValue value, CancellationToken cancellationToken)
{
this.value = value;
this.cancellationToken = cancellationToken;
this.called = false;
}
public TValue Current => value;
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
if (!called)
{
called = true;
return CompletedTasks.True;
}
return CompletedTasks.False;
}
public UniTask DisposeAsync()
{
return default;
}
}
}
}

View File

@ -1,6 +1,7 @@
namespace Cysharp.Threading.Tasks.Linq namespace Cysharp.Threading.Tasks.Linq
{ {
internal sealed class Single // avoid conflicts with System.Single
internal sealed class SingleOperator
{ {
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
<#@ 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 types = new[]
{
typeof(int),
typeof(long),
typeof(float),
typeof(double),
typeof(decimal),
typeof(int?),
typeof(long?),
typeof(float?),
typeof(double?),
typeof(decimal?),
};
Func<Type, bool> IsNullable = x => x.IsGenericType;
Func<Type, string> TypeName = x => IsNullable(x) ? x.GetGenericArguments()[0].Name + "?" : x.Name;
Func<Type, string> WithSuffix = x => IsNullable(x) ? ".GetValueOrDefault()" : "";
#>
using System;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
<# foreach(var t in types) { #>
public static UniTask<<#= TypeName(t) #>> SumAsync(this IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
return Sum.InvokeAsync(source, cancellationToken);
}
public static UniTask<<#= TypeName(t) #>> SumAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(selector));
return Sum.InvokeAsync(source, selector, cancellationToken);
}
public static UniTask<<#= TypeName(t) #>> SumAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(selector));
return Sum.InvokeAsync(source, selector, cancellationToken);
}
public static UniTask<<#= TypeName(t) #>> SumAwaitCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(selector));
return Sum.InvokeAsync(source, selector, cancellationToken);
}
<# } #>
}
internal static class Sum
{
<# foreach(var t in types) { #>
public static async UniTask<<#= TypeName(t) #>> InvokeAsync(IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken)
{
<#= TypeName(t) #> sum = default;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
sum += e.Current<#= WithSuffix(t) #>;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return sum;
}
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken)
{
<#= TypeName(t) #> sum = default;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
sum += selector(e.Current)<#= WithSuffix(t) #>;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return sum;
}
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
{
<#= TypeName(t) #> sum = default;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
sum += (await selector(e.Current))<#= WithSuffix(t) #>;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return sum;
}
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
{
<#= TypeName(t) #> sum = default;
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
sum += (await selector(e.Current, cancellationToken))<#= WithSuffix(t) #>;
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
return sum;
}
<# } #>
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,4 +10,31 @@
<Compile Include="..\UniTask\Assets\Plugins\UniTask\**\*.cs" Exclude="..\UniTask\Assets\Plugins\UniTask\Triggers\*.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;&#xD;&#xA; &#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\UnityEqualityComparer.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\DiagnosticsExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\PlayerLoopRunner.cs;&#xD;&#xA; &#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\CancellationTokenSourceExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\EnumeratorAsyncExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\PlayerLoopHelper.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Delay.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Run.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Bridge.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.WaitUntil.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.uGUI.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.MonoBehaviour.cs;&#xD;&#xA; " /> <Compile Include="..\UniTask\Assets\Plugins\UniTask\**\*.cs" Exclude="..\UniTask\Assets\Plugins\UniTask\Triggers\*.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;&#xD;&#xA; &#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\UnityEqualityComparer.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\DiagnosticsExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\Internal\PlayerLoopRunner.cs;&#xD;&#xA; &#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\CancellationTokenSourceExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\EnumeratorAsyncExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\PlayerLoopHelper.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Delay.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Run.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.Bridge.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UniTask.WaitUntil.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.uGUI.cs;&#xD;&#xA; ..\UniTask\Assets\Plugins\UniTask\UnityAsyncExtensions.MonoBehaviour.cs;&#xD;&#xA; " />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="Linq\Sum.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Sum.tt</DependentUpon>
</None>
</ItemGroup>
<ItemGroup>
<None Update="Linq\Sum.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Sum.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Linq\Sum.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Sum.tt</DependentUpon>
</Compile>
</ItemGroup>
</Project> </Project>

View File

@ -32,14 +32,27 @@ namespace NetCoreSandbox
static async Task Main(string[] args) static async Task Main(string[] args)
{ {
var xs = await UniTaskAsyncEnumerable.Range(0, 0).ToArrayAsync();
Console.WriteLine(xs);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
// Enumerable.Sum(
await foreach (var item in UniTaskAsyncEnumerable.Range(1, 3).WithCancellation(cts.Token))
{ //await foreach (var item in UniTaskAsyncEnumerable.Range(1, 3).WithCancellation(cts.Token))
Console.WriteLine(item); //{
cts.Cancel(); // Console.WriteLine(item);
} // cts.Cancel();
//}
//AsyncEnumerable.SumAsync(
var a = await UniTaskAsyncEnumerable.Range(1, 100).SumAsync();
Console.WriteLine(a);
/* /*

View File

@ -0,0 +1,65 @@
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace UniTask.NetCoreTests.Linq
{
public class Factory
{
[Theory]
[InlineData(0, 10)]
[InlineData(0, 0)]
[InlineData(1, 5)]
[InlineData(1, 0)]
[InlineData(0, 11)]
[InlineData(1, 11)]
public async Task RangeTest(int start, int count)
{
var xs = await UniTaskAsyncEnumerable.Range(start, count).ToArrayAsync();
var ys = Enumerable.Range(start, count).ToArray();
xs.Should().BeEquivalentTo(ys);
}
[Theory]
[InlineData("foo", 0)]
[InlineData("bar", 1)]
[InlineData("baz", 3)]
[InlineData("foobar", 10)]
[InlineData("foobarbaz", 11)]
public async Task RepeatTest(string value, int count)
{
var xs = await UniTaskAsyncEnumerable.Repeat(value, count).ToArrayAsync();
var ys = Enumerable.Repeat(value, count).ToArray();
xs.Should().BeEquivalentTo(ys);
}
[Fact]
public async Task EmptyTest()
{
var xs = await UniTaskAsyncEnumerable.Empty<int>().ToArrayAsync();
var ys = Enumerable.Empty<int>().ToArray();
xs.Should().BeEquivalentTo(ys);
}
[Theory]
[InlineData(100)]
[InlineData((string)null)]
[InlineData("foo")]
public async Task ReturnTest<T>(T value)
{
var xs = await UniTaskAsyncEnumerable.Return(value).ToArrayAsync();
xs.Length.Should().Be(1);
xs[0].Should().Be(value);
}
}
}

View File

@ -9,10 +9,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="xunit" Version="2.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.0.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using Xunit;
namespace UniTask.NetCoreTests
{
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
}