zip
parent
4d13523df7
commit
c0da316cb4
|
@ -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,7 +150,9 @@ 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))
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -149,6 +177,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||||
self.completionSource.TrySetResult(false);
|
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,9 +268,20 @@ 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))
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter();
|
self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
self.completionSource.TrySetException(ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (self.secondAwaiter.IsCompleted)
|
if (self.secondAwaiter.IsCompleted)
|
||||||
{
|
{
|
||||||
SecondMoveNextCore(self);
|
SecondMoveNextCore(self);
|
||||||
|
@ -256,22 +296,31 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||||
self.completionSource.TrySetResult(false);
|
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();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
self.resultAwaiter = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current).GetAwaiter();
|
||||||
if (self.resultAwaiter.IsCompleted)
|
if (self.resultAwaiter.IsCompleted)
|
||||||
{
|
{
|
||||||
UnwrapResultTask(self);
|
ResultAwaitCore(self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.resultAwaiter.SourceOnCompleted(unwrapResultTaskDelegate, self);
|
self.resultAwaiter.SourceOnCompleted(resultAwaitCoreDelegate, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
self.completionSource.TrySetException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -279,19 +328,15 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||||
self.completionSource.TrySetResult(false);
|
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)
|
||||||
{
|
{
|
||||||
|
@ -302,6 +347,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||||
self.completionSource.TrySetResult(true);
|
self.completionSource.TrySetResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async UniTask DisposeAsync()
|
public async UniTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue