master
neuecc 2020-05-11 02:29:23 +09:00
parent 4d13523df7
commit c0da316cb4
2 changed files with 409 additions and 77 deletions

View File

@ -1,4 +1,5 @@
using System; using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading; using System.Threading;
namespace Cysharp.Threading.Tasks.Linq namespace Cysharp.Threading.Tasks.Linq
@ -8,12 +9,37 @@ namespace Cysharp.Threading.Tasks.Linq
public static IUniTaskAsyncEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second) public static IUniTaskAsyncEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second)
{ {
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
return Zip(first, second, (x, y) => (x, y)); return Zip(first, second, (x, y) => (x, y));
} }
public static IUniTaskAsyncEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector) public static IUniTaskAsyncEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{ {
return new Cysharp.Threading.Tasks.Linq.Zip<TFirst, TSecond, TResult>(first, second, resultSelector); Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
return new Zip<TFirst, TSecond, TResult>(first, second, resultSelector);
}
public static IUniTaskAsyncEnumerable<TResult> ZipAwait<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, UniTask<TResult>> selector)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(selector, nameof(selector));
return new ZipAwait<TFirst, TSecond, TResult>(first, second, selector);
}
public static IUniTaskAsyncEnumerable<TResult> ZipAwaitWithCancellation<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> selector)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(selector, nameof(selector));
return new ZipAwaitWithCancellation<TFirst, TSecond, TResult>(first, second, selector);
} }
} }
@ -124,30 +150,33 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
var self = (Enumerator)state; var self = (Enumerator)state;
if (self.secondAwaiter.GetResult()) if (self.TryGetResult(self.secondAwaiter, out var result))
{ {
try if (result)
{ {
self.Current = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current); try
} {
catch (Exception ex) self.Current = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current);
{ }
self.completionSource.TrySetException(ex); catch (Exception ex)
} {
self.completionSource.TrySetException(ex);
}
if (self.cancellationToken.IsCancellationRequested) if (self.cancellationToken.IsCancellationRequested)
{ {
self.completionSource.TrySetCanceled(self.cancellationToken); self.completionSource.TrySetCanceled(self.cancellationToken);
}
else
{
self.completionSource.TrySetResult(true);
}
} }
else else
{ {
self.completionSource.TrySetResult(true); self.completionSource.TrySetResult(false);
} }
} }
else
{
self.completionSource.TrySetResult(false);
}
} }
public async UniTask DisposeAsync() public async UniTask DisposeAsync()
@ -186,7 +215,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore; static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore;
static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore; static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore;
static readonly Action<object> unwrapResultTaskDelegate = UnwrapResultTask; static readonly Action<object> resultAwaitCoreDelegate = ResultAwaitCore;
readonly IUniTaskAsyncEnumerable<TFirst> first; readonly IUniTaskAsyncEnumerable<TFirst> first;
readonly IUniTaskAsyncEnumerable<TSecond> second; readonly IUniTaskAsyncEnumerable<TSecond> second;
@ -239,67 +268,84 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
var self = (Enumerator)state; var self = (Enumerator)state;
if (self.firstAwaiter.GetResult()) if (self.TryGetResult(self.firstAwaiter, out var result))
{ {
self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter(); if (result)
if (self.secondAwaiter.IsCompleted)
{ {
SecondMoveNextCore(self); try
{
self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter();
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
return;
}
if (self.secondAwaiter.IsCompleted)
{
SecondMoveNextCore(self);
}
else
{
self.secondAwaiter.SourceOnCompleted(secondMoveNextCoreDelegate, self);
}
} }
else else
{ {
self.secondAwaiter.SourceOnCompleted(secondMoveNextCoreDelegate, self); self.completionSource.TrySetResult(false);
} }
} }
else
{
self.completionSource.TrySetResult(false);
}
} }
static void SecondMoveNextCore(object state) static void SecondMoveNextCore(object state)
{ {
var self = (Enumerator)state; var self = (Enumerator)state;
if (self.secondAwaiter.GetResult()) if (self.TryGetResult(self.secondAwaiter, out var result))
{ {
var task = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current); if (result)
self.resultAwaiter = task.GetAwaiter();
if (self.resultAwaiter.IsCompleted)
{ {
UnwrapResultTask(self); try
{
self.resultAwaiter = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current).GetAwaiter();
if (self.resultAwaiter.IsCompleted)
{
ResultAwaitCore(self);
}
else
{
self.resultAwaiter.SourceOnCompleted(resultAwaitCoreDelegate, self);
}
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
} }
else else
{ {
self.resultAwaiter.SourceOnCompleted(unwrapResultTaskDelegate, self); self.completionSource.TrySetResult(false);
} }
} }
else
{
self.completionSource.TrySetResult(false);
}
} }
static void UnwrapResultTask(object state) static void ResultAwaitCore(object state)
{ {
var self = (Enumerator)state; var self = (Enumerator)state;
try if (self.TryGetResult(self.resultAwaiter, out var result))
{ {
self.Current = self.resultAwaiter.GetResult(); self.Current = result;
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
if (self.cancellationToken.IsCancellationRequested) if (self.cancellationToken.IsCancellationRequested)
{ {
self.completionSource.TrySetCanceled(self.cancellationToken); self.completionSource.TrySetCanceled(self.cancellationToken);
} }
else else
{ {
self.completionSource.TrySetResult(true); self.completionSource.TrySetResult(true);
}
} }
} }
@ -317,4 +363,173 @@ namespace Cysharp.Threading.Tasks.Linq
} }
} }
internal sealed class ZipAwaitWithCancellation<TFirst, TSecond, TResult> : IUniTaskAsyncEnumerable<TResult>
{
readonly IUniTaskAsyncEnumerable<TFirst> first;
readonly IUniTaskAsyncEnumerable<TSecond> second;
readonly Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector;
public ZipAwaitWithCancellation(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector)
{
this.first = first;
this.second = second;
this.resultSelector = resultSelector;
}
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(first, second, resultSelector, cancellationToken);
}
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore;
static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore;
static readonly Action<object> resultAwaitCoreDelegate = ResultAwaitCore;
readonly IUniTaskAsyncEnumerable<TFirst> first;
readonly IUniTaskAsyncEnumerable<TSecond> second;
readonly Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector;
CancellationToken cancellationToken;
IUniTaskAsyncEnumerator<TFirst> firstEnumerator;
IUniTaskAsyncEnumerator<TSecond> secondEnumerator;
UniTask<bool>.Awaiter firstAwaiter;
UniTask<bool>.Awaiter secondAwaiter;
UniTask<TResult>.Awaiter resultAwaiter;
public Enumerator(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
{
this.first = first;
this.second = second;
this.resultSelector = resultSelector;
this.cancellationToken = cancellationToken;
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
completionSource.Reset();
if (firstEnumerator == null)
{
firstEnumerator = first.GetAsyncEnumerator(cancellationToken);
secondEnumerator = second.GetAsyncEnumerator(cancellationToken);
}
firstAwaiter = firstEnumerator.MoveNextAsync().GetAwaiter();
if (firstAwaiter.IsCompleted)
{
FirstMoveNextCore(this);
}
else
{
firstAwaiter.SourceOnCompleted(firstMoveNextCoreDelegate, this);
}
return new UniTask<bool>(this, completionSource.Version);
}
static void FirstMoveNextCore(object state)
{
var self = (Enumerator)state;
if (self.TryGetResult(self.firstAwaiter, out var result))
{
if (result)
{
try
{
self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter();
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
return;
}
if (self.secondAwaiter.IsCompleted)
{
SecondMoveNextCore(self);
}
else
{
self.secondAwaiter.SourceOnCompleted(secondMoveNextCoreDelegate, self);
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
static void SecondMoveNextCore(object state)
{
var self = (Enumerator)state;
if (self.TryGetResult(self.secondAwaiter, out var result))
{
if (result)
{
try
{
self.resultAwaiter = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current, self.cancellationToken).GetAwaiter();
if (self.resultAwaiter.IsCompleted)
{
ResultAwaitCore(self);
}
else
{
self.resultAwaiter.SourceOnCompleted(resultAwaitCoreDelegate, self);
}
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
static void ResultAwaitCore(object state)
{
var self = (Enumerator)state;
if (self.TryGetResult(self.resultAwaiter, out var result))
{
self.Current = result;
if (self.cancellationToken.IsCancellationRequested)
{
self.completionSource.TrySetCanceled(self.cancellationToken);
}
else
{
self.completionSource.TrySetResult(true);
}
}
}
public async UniTask DisposeAsync()
{
if (firstEnumerator != null)
{
await firstEnumerator.DisposeAsync();
}
if (secondEnumerator != null)
{
await secondEnumerator.DisposeAsync();
}
}
}
}
} }

View File

@ -37,6 +37,58 @@ namespace NetCoreTests.Linq
} }
} }
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(9)]
public async Task Select(int count)
{
{
var xs = await UniTaskAsyncEnumerable.Range(1, count).Select(x => x * x).ToArrayAsync();
var ys = Enumerable.Range(1, count).Select(x => x * x).ToArray();
xs.Should().BeEquivalentTo(ys);
var zs = await UniTaskAsyncEnumerable.Range(1, count).SelectAwait((x) => UniTask.Run(() => x * x)).ToArrayAsync();
zs.Should().BeEquivalentTo(ys);
}
{
var xs = await UniTaskAsyncEnumerable.Range(1, count).Select((x, i) => x * x * i).ToArrayAsync();
var ys = Enumerable.Range(1, count).Select((x, i) => x * x * i).ToArray();
xs.Should().BeEquivalentTo(ys);
var zs = await UniTaskAsyncEnumerable.Range(1, count).SelectAwait((x, i) => UniTask.Run(() => x * x * i)).ToArrayAsync();
zs.Should().BeEquivalentTo(ys);
}
}
[Fact]
public async Task SelectException()
{
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.Select(x => UniTaskAsyncEnumerable.Range(0, 1)).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
// await
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.SelectAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(0, 1))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
// cancel
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.SelectAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(0, 1))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
}
[Theory] [Theory]
[InlineData(0, 9)] // empty + exists [InlineData(0, 9)] // empty + exists
[InlineData(9, 0)] // exists + empty [InlineData(9, 0)] // exists + empty
@ -44,69 +96,69 @@ namespace NetCoreTests.Linq
public async Task SelectMany(int leftCount, int rightCount) public async Task SelectMany(int leftCount, int rightCount)
{ {
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount * x)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount), (x, y) => x * y).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount * x), (x, y) => x * y).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
// await // await
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount))).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount))).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)), (x, y) => UniTask.Run(() => x * y)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
// with cancel // with cancel
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount))).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount))).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x)).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount * x)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
{ {
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync(); var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount * x)), (x, y, _) => UniTask.Run(() => x * y)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount * x), (x, y) => x * y).ToArray();
xs.Should().BeEquivalentTo(ys); xs.Should().BeEquivalentTo(ys);
} }
} }
@ -155,5 +207,70 @@ namespace NetCoreTests.Linq
} }
[Theory]
[InlineData(0, 9)] // empty + exists
[InlineData(9, 0)] // exists + empty
[InlineData(9, 9)] // same
[InlineData(9, 4)] // leftlong
[InlineData(4, 9)] // rightlong
public async Task Zip(int leftCount, int rightCount)
{
{
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).Zip(UniTaskAsyncEnumerable.Range(99, rightCount)).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
xs.Should().BeEquivalentTo(ys);
}
{
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).ZipAwait(UniTaskAsyncEnumerable.Range(99, rightCount), (x, y) => UniTask.Run(() => (x, y))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
xs.Should().BeEquivalentTo(ys);
}
{
var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).ZipAwaitWithCancellation(UniTaskAsyncEnumerable.Range(99, rightCount), (x, y, _) => UniTask.Run(() => (x, y))).ToArrayAsync();
var ys = Enumerable.Range(1, leftCount).Zip(Enumerable.Range(99, rightCount)).ToArray();
xs.Should().BeEquivalentTo(ys);
}
}
[Fact]
public async Task ZipException()
{
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.Zip(UniTaskAsyncEnumerable.Range(1, 10)).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
foreach (var item in UniTaskTestException.Throws())
{
var xs = UniTaskAsyncEnumerable.Range(1, 10).Zip(item).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
// a
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.ZipAwait(UniTaskAsyncEnumerable.Range(1, 10), (x, y) => UniTask.Run(() => (x, y))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
foreach (var item in UniTaskTestException.Throws())
{
var xs = UniTaskAsyncEnumerable.Range(1, 10).ZipAwait(item, (x, y) => UniTask.Run(() => (x, y))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
// c
foreach (var item in UniTaskTestException.Throws())
{
var xs = item.ZipAwaitWithCancellation(UniTaskAsyncEnumerable.Range(1, 10), (x, y, c) => UniTask.Run(() => (x, y))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
foreach (var item in UniTaskTestException.Throws())
{
var xs = UniTaskAsyncEnumerable.Range(1, 10).ZipAwaitWithCancellation(item, (x, y, c) => UniTask.Run(() => (x, y))).ToArrayAsync();
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs);
}
}
} }
} }