From c0da316cb441bd404f6e4d1a085ce7954641f67e Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 11 May 2020 02:29:23 +0900 Subject: [PATCH] zip --- src/UniTask.NetCore/Linq/Zip.cs | 321 ++++++++++++++++---- src/UniTask.NetCoreTests/Linq/Projection.cs | 165 ++++++++-- 2 files changed, 409 insertions(+), 77 deletions(-) diff --git a/src/UniTask.NetCore/Linq/Zip.cs b/src/UniTask.NetCore/Linq/Zip.cs index e3fdefb..d646d78 100644 --- a/src/UniTask.NetCore/Linq/Zip.cs +++ b/src/UniTask.NetCore/Linq/Zip.cs @@ -1,4 +1,5 @@ -using System; +using Cysharp.Threading.Tasks.Internal; +using System; using System.Threading; namespace Cysharp.Threading.Tasks.Linq @@ -8,12 +9,37 @@ namespace Cysharp.Threading.Tasks.Linq public static IUniTaskAsyncEnumerable<(TFirst First, TSecond Second)> Zip(this IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second) { + Error.ThrowArgumentNullException(first, nameof(first)); + Error.ThrowArgumentNullException(second, nameof(second)); + return Zip(first, second, (x, y) => (x, y)); } public static IUniTaskAsyncEnumerable Zip(this IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second, Func resultSelector) { - return new Cysharp.Threading.Tasks.Linq.Zip(first, second, resultSelector); + Error.ThrowArgumentNullException(first, nameof(first)); + Error.ThrowArgumentNullException(second, nameof(second)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + + return new Zip(first, second, resultSelector); + } + + public static IUniTaskAsyncEnumerable ZipAwait(this IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second, Func> selector) + { + Error.ThrowArgumentNullException(first, nameof(first)); + Error.ThrowArgumentNullException(second, nameof(second)); + Error.ThrowArgumentNullException(selector, nameof(selector)); + + return new ZipAwait(first, second, selector); + } + + public static IUniTaskAsyncEnumerable ZipAwaitWithCancellation(this IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second, Func> selector) + { + Error.ThrowArgumentNullException(first, nameof(first)); + Error.ThrowArgumentNullException(second, nameof(second)); + Error.ThrowArgumentNullException(selector, nameof(selector)); + + return new ZipAwaitWithCancellation(first, second, selector); } } @@ -124,30 +150,33 @@ namespace Cysharp.Threading.Tasks.Linq { 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); - } - catch (Exception ex) - { - self.completionSource.TrySetException(ex); - } + try + { + self.Current = self.resultSelector(self.firstEnumerator.Current, self.secondEnumerator.Current); + } + catch (Exception ex) + { + self.completionSource.TrySetException(ex); + } - if (self.cancellationToken.IsCancellationRequested) - { - self.completionSource.TrySetCanceled(self.cancellationToken); + if (self.cancellationToken.IsCancellationRequested) + { + self.completionSource.TrySetCanceled(self.cancellationToken); + } + else + { + self.completionSource.TrySetResult(true); + } } else { - self.completionSource.TrySetResult(true); + self.completionSource.TrySetResult(false); } } - else - { - self.completionSource.TrySetResult(false); - } } public async UniTask DisposeAsync() @@ -186,7 +215,7 @@ namespace Cysharp.Threading.Tasks.Linq { static readonly Action firstMoveNextCoreDelegate = FirstMoveNextCore; static readonly Action secondMoveNextCoreDelegate = SecondMoveNextCore; - static readonly Action unwrapResultTaskDelegate = UnwrapResultTask; + static readonly Action resultAwaitCoreDelegate = ResultAwaitCore; readonly IUniTaskAsyncEnumerable first; readonly IUniTaskAsyncEnumerable second; @@ -239,67 +268,84 @@ namespace Cysharp.Threading.Tasks.Linq { var self = (Enumerator)state; - if (self.firstAwaiter.GetResult()) + if (self.TryGetResult(self.firstAwaiter, out var result)) { - self.secondAwaiter = self.secondEnumerator.MoveNextAsync().GetAwaiter(); - if (self.secondAwaiter.IsCompleted) + if (result) { - 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 { - self.secondAwaiter.SourceOnCompleted(secondMoveNextCoreDelegate, self); + self.completionSource.TrySetResult(false); } } - else - { - self.completionSource.TrySetResult(false); - } } static void SecondMoveNextCore(object 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); - self.resultAwaiter = task.GetAwaiter(); - if (self.resultAwaiter.IsCompleted) + if (result) { - 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 { - 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; - try + if (self.TryGetResult(self.resultAwaiter, out var result)) { - self.Current = self.resultAwaiter.GetResult(); - } - catch (Exception ex) - { - self.completionSource.TrySetException(ex); - } + self.Current = result; - if (self.cancellationToken.IsCancellationRequested) - { - self.completionSource.TrySetCanceled(self.cancellationToken); - } - else - { - self.completionSource.TrySetResult(true); + if (self.cancellationToken.IsCancellationRequested) + { + self.completionSource.TrySetCanceled(self.cancellationToken); + } + else + { + self.completionSource.TrySetResult(true); + } } } @@ -317,4 +363,173 @@ namespace Cysharp.Threading.Tasks.Linq } } + internal sealed class ZipAwaitWithCancellation : IUniTaskAsyncEnumerable + { + readonly IUniTaskAsyncEnumerable first; + readonly IUniTaskAsyncEnumerable second; + readonly Func> resultSelector; + + public ZipAwaitWithCancellation(IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second, Func> resultSelector) + { + this.first = first; + this.second = second; + this.resultSelector = resultSelector; + } + + public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + return new Enumerator(first, second, resultSelector, cancellationToken); + } + + sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator + { + static readonly Action firstMoveNextCoreDelegate = FirstMoveNextCore; + static readonly Action secondMoveNextCoreDelegate = SecondMoveNextCore; + static readonly Action resultAwaitCoreDelegate = ResultAwaitCore; + + readonly IUniTaskAsyncEnumerable first; + readonly IUniTaskAsyncEnumerable second; + readonly Func> resultSelector; + + CancellationToken cancellationToken; + + IUniTaskAsyncEnumerator firstEnumerator; + IUniTaskAsyncEnumerator secondEnumerator; + + UniTask.Awaiter firstAwaiter; + UniTask.Awaiter secondAwaiter; + UniTask.Awaiter resultAwaiter; + + public Enumerator(IUniTaskAsyncEnumerable first, IUniTaskAsyncEnumerable second, Func> resultSelector, CancellationToken cancellationToken) + { + this.first = first; + this.second = second; + this.resultSelector = resultSelector; + this.cancellationToken = cancellationToken; + } + + public TResult Current { get; private set; } + + public UniTask 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(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(); + } + } + } + } } \ No newline at end of file diff --git a/src/UniTask.NetCoreTests/Linq/Projection.cs b/src/UniTask.NetCoreTests/Linq/Projection.cs index 2b411b2..2ec717a 100644 --- a/src/UniTask.NetCoreTests/Linq/Projection.cs +++ b/src/UniTask.NetCoreTests/Linq/Projection.cs @@ -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(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(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(async () => await xs); + } + } + + [Theory] [InlineData(0, 9)] // empty + exists [InlineData(9, 0)] // exists + empty @@ -44,69 +96,69 @@ namespace NetCoreTests.Linq public async Task SelectMany(int leftCount, int rightCount) { { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount)).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); + 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 * x)).ToArray(); xs.Should().BeEquivalentTo(ys); } { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany((i, x) => UniTaskAsyncEnumerable.Range(99 * i, rightCount)).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); + 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 * x)).ToArray(); xs.Should().BeEquivalentTo(ys); } { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectMany(x => UniTaskAsyncEnumerable.Range(99, rightCount), (x, y) => x * y).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); 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 ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); xs.Should().BeEquivalentTo(ys); } // await { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait(x => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount))).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); + 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 * x)).ToArray(); xs.Should().BeEquivalentTo(ys); } { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwait((i, x) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount))).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); + 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 * x)).ToArray(); 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 ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); 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 ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); xs.Should().BeEquivalentTo(ys); } // with cancel { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99, rightCount))).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount)).ToArray(); + 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 * x)).ToArray(); xs.Should().BeEquivalentTo(ys); } { - var xs = await UniTaskAsyncEnumerable.Range(1, leftCount).SelectManyAwaitWithCancellation((i, x, _) => UniTask.Run(() => UniTaskAsyncEnumerable.Range(99 * i, rightCount))).ToArrayAsync(); - var ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount)).ToArray(); + 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 * x)).ToArray(); 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 ys = Enumerable.Range(1, leftCount).SelectMany(x => Enumerable.Range(99, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); 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 ys = Enumerable.Range(1, leftCount).SelectMany((i, x) => Enumerable.Range(99 * i, rightCount), (x, y) => x * y).ToArray(); + 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), (x, y) => x * y).ToArray(); 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(async () => await xs); + } + foreach (var item in UniTaskTestException.Throws()) + { + var xs = UniTaskAsyncEnumerable.Range(1, 10).Zip(item).ToArrayAsync(); + await Assert.ThrowsAsync(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(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(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(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(async () => await xs); + } + } } }