// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace System.Linq
{
public static partial class AsyncEnumerable
{
#if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
// https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.zip?view=net-9.0-pp#system-linq-asyncenumerable-zip-2(system-collections-generic-iasyncenumerable((-0))-system-collections-generic-iasyncenumerable((-1)))
///
/// Merges two async-enumerable sequences into one async-enumerable sequence by combining their elements in a pairwise fashion.
///
/// The type of the elements in the first source sequence.
/// The type of the elements in the second source sequence.
/// First async-enumerable source.
/// Second async-enumerable source.
/// An async-enumerable sequence containing the result of pairwise combining the elements of the first and second source using the specified result selector function.
/// or is null.
public static IAsyncEnumerable<(TFirst First, TSecond Second)> Zip(this IAsyncEnumerable first, IAsyncEnumerable second)
{
if (first == null)
throw Error.ArgumentNull(nameof(first));
if (second == null)
throw Error.ArgumentNull(nameof(second));
return Core(first, second);
static async IAsyncEnumerable<(TFirst, TSecond)> Core(IAsyncEnumerable first, IAsyncEnumerable second, [System.Runtime.CompilerServices.EnumeratorCancellation]CancellationToken cancellationToken = default)
{
await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
while (await e1.MoveNextAsync() && await e2.MoveNextAsync())
{
yield return (e1.Current, e2.Current);
}
}
}
// https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.zip?view=net-9.0-pp#system-linq-asyncenumerable-zip-3(system-collections-generic-iasyncenumerable((-0))-system-collections-generic-iasyncenumerable((-1))-system-func((-0-1-2)))
///
/// Merges two async-enumerable sequences into one async-enumerable sequence by combining their elements in a pairwise fashion.
///
/// The type of the elements in the first source sequence.
/// The type of the elements in the second source sequence.
/// The type of the elements in the result sequence, returned by the selector function.
/// First async-enumerable source.
/// Second async-enumerable source.
/// Function to invoke for each consecutive pair of elements from the first and second source.
/// An async-enumerable sequence containing the result of pairwise combining the elements of the first and second source using the specified result selector function.
/// or or is null.
public static IAsyncEnumerable Zip(this IAsyncEnumerable first, IAsyncEnumerable second, Func selector)
{
if (first == null)
throw Error.ArgumentNull(nameof(first));
if (second == null)
throw Error.ArgumentNull(nameof(second));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
return Core(first, second, selector);
static async IAsyncEnumerable Core(IAsyncEnumerable first, IAsyncEnumerable second, Func selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
while (await e1.MoveNextAsync() && await e2.MoveNextAsync())
{
yield return selector(e1.Current, e2.Current);
}
}
}
#endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
///
/// Merges two async-enumerable sequences into one async-enumerable sequence by combining their elements in a pairwise fashion.
///
/// The type of the elements in the first source sequence.
/// The type of the elements in the second source sequence.
/// The type of the elements in the result sequence, returned by the selector function.
/// First async-enumerable source.
/// Second async-enumerable source.
/// An asynchronous function to invoke and await for each consecutive pair of elements from the first and second source.
/// An async-enumerable sequence containing the result of pairwise combining the elements of the first and second source using the specified result selector function.
/// or or is null.
[GenerateAsyncOverload]
[Obsolete("Use Zip. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ZipAwait functionality now exists as overloads of Zip.")]
private static IAsyncEnumerable ZipAwaitCore(this IAsyncEnumerable first, IAsyncEnumerable second, Func> selector)
{
if (first == null)
throw Error.ArgumentNull(nameof(first));
if (second == null)
throw Error.ArgumentNull(nameof(second));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
return Core(first, second, selector);
static async IAsyncEnumerable Core(IAsyncEnumerable first, IAsyncEnumerable second, Func> selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
while (await e1.MoveNextAsync() && await e2.MoveNextAsync())
{
yield return await selector(e1.Current, e2.Current).ConfigureAwait(false);
}
}
}
#if !NO_DEEP_CANCELLATION
[GenerateAsyncOverload]
[Obsolete("Use Zip. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the ZipAwaitWithCancellation functionality now exists as overloads of Zip.")]
private static IAsyncEnumerable ZipAwaitWithCancellationCore(this IAsyncEnumerable first, IAsyncEnumerable second, Func> selector)
{
if (first == null)
throw Error.ArgumentNull(nameof(first));
if (second == null)
throw Error.ArgumentNull(nameof(second));
if (selector == null)
throw Error.ArgumentNull(nameof(selector));
return Core(first, second, selector);
static async IAsyncEnumerable Core(IAsyncEnumerable first, IAsyncEnumerable second, Func> selector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await using var e1 = first.GetConfiguredAsyncEnumerator(cancellationToken, false);
await using var e2 = second.GetConfiguredAsyncEnumerator(cancellationToken, false);
while (await e1.MoveNextAsync() && await e2.MoveNextAsync())
{
yield return await selector(e1.Current, e2.Current, cancellationToken).ConfigureAwait(false);
}
}
}
#endif
}
}