// 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
{
#if REFERENCE_ASSEMBLY
public static partial class AsyncEnumerableDeprecated
#else
public static partial class AsyncEnumerable
#endif
{
#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 an overload of Zip. You will need to modify your callback to take an additional CancellationToken argument.")]
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 an overload 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
}
}