2026-01-07 14:47:20 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2026-01-08 09:14:46 +00:00
|
|
|
using System.Linq;
|
2026-01-13 14:24:36 +00:00
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Threading;
|
2026-01-07 14:47:20 +00:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace SharpCompress;
|
|
|
|
|
|
2026-01-08 09:14:46 +00:00
|
|
|
public static class AsyncEnumerableEx
|
|
|
|
|
{
|
|
|
|
|
public static async IAsyncEnumerable<T> Empty<T>()
|
|
|
|
|
where T : notnull
|
|
|
|
|
{
|
2026-01-08 09:41:48 +00:00
|
|
|
await Task.CompletedTask;
|
|
|
|
|
yield break;
|
2026-01-08 09:14:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 09:39:04 +00:00
|
|
|
public static class EnumerableExtensions
|
|
|
|
|
{
|
|
|
|
|
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> source)
|
|
|
|
|
{
|
|
|
|
|
await Task.CompletedTask;
|
|
|
|
|
foreach (var item in source)
|
|
|
|
|
{
|
|
|
|
|
yield return item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 14:47:20 +00:00
|
|
|
public static class AsyncEnumerableExtensions
|
|
|
|
|
{
|
2026-01-13 14:28:45 +00:00
|
|
|
public static async IAsyncEnumerable<TResult> Select<T, TResult>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
Func<T, TResult> selector)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var element in source)
|
|
|
|
|
{
|
|
|
|
|
yield return selector(element);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public static async ValueTask<int> CountAsync<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
await using var e = source.GetAsyncEnumerator(cancellationToken);
|
|
|
|
|
|
|
|
|
|
var count = 0;
|
|
|
|
|
while (await e.MoveNextAsync())
|
|
|
|
|
{
|
|
|
|
|
checked { count++; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 14:24:36 +00:00
|
|
|
public static async IAsyncEnumerable<T> TakeAsync<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
int count)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var element in source)
|
|
|
|
|
{
|
|
|
|
|
yield return element;
|
|
|
|
|
|
|
|
|
|
if (--count == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 13:45:21 +00:00
|
|
|
public static async ValueTask<List<T>> ToListAsync<T>(this IAsyncEnumerable<T> source)
|
2026-01-07 14:47:20 +00:00
|
|
|
{
|
2026-01-12 13:45:21 +00:00
|
|
|
var list = new List<T>();
|
|
|
|
|
await foreach (var item in source)
|
2026-01-08 09:39:04 +00:00
|
|
|
{
|
2026-01-12 13:45:21 +00:00
|
|
|
list.Add(item);
|
2026-01-08 09:39:04 +00:00
|
|
|
}
|
2026-01-12 13:45:21 +00:00
|
|
|
return list;
|
|
|
|
|
}
|
2026-01-08 09:41:48 +00:00
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
public static async IAsyncEnumerable<TResult> CastAsync<TResult>(
|
|
|
|
|
this IAsyncEnumerable<object?> source
|
|
|
|
|
)
|
2026-01-12 13:45:21 +00:00
|
|
|
where TResult : class
|
|
|
|
|
{
|
|
|
|
|
await foreach (var item in source)
|
2026-01-08 09:14:46 +00:00
|
|
|
{
|
2026-01-12 13:45:21 +00:00
|
|
|
yield return (item as TResult).NotNull();
|
2026-01-08 09:14:46 +00:00
|
|
|
}
|
2026-01-12 13:45:21 +00:00
|
|
|
}
|
2026-01-08 09:41:48 +00:00
|
|
|
|
2026-01-12 13:45:21 +00:00
|
|
|
public static async ValueTask<TAccumulate> AggregateAsync<TAccumulate, T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
TAccumulate seed,
|
|
|
|
|
Func<TAccumulate, T, TAccumulate> func
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
TAccumulate result = seed;
|
|
|
|
|
await foreach (var element in source)
|
|
|
|
|
{
|
|
|
|
|
result = func(result, element);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
public static async ValueTask<bool> AllAsync<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
Func<T, bool> predicate
|
|
|
|
|
)
|
2026-01-12 13:45:21 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
await foreach (var item in source)
|
2026-01-08 09:14:46 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
if (!predicate(item))
|
2026-01-08 09:14:46 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
return false;
|
2026-01-08 09:14:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-08 09:41:48 +00:00
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IAsyncEnumerable<T> Where<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
Func<T, bool> predicate
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return WhereIterator(source, predicate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static async IAsyncEnumerable<T> WhereIterator<T>(
|
|
|
|
|
IAsyncEnumerable<T> source,
|
|
|
|
|
Func<T, bool> predicate
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var item in source)
|
2026-01-07 14:47:20 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
if (predicate(item))
|
2026-01-07 14:47:20 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
yield return item;
|
2026-01-07 14:47:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-12 14:14:46 +00:00
|
|
|
}
|
2026-01-07 14:47:20 +00:00
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
public static async IAsyncEnumerable<T> WhereAsync<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
|
|
|
|
Func<T, bool> predicate
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var item in source)
|
2026-01-12 12:08:25 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
if (predicate(item))
|
2026-01-12 12:08:25 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
yield return item;
|
2026-01-12 12:08:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-12 14:14:46 +00:00
|
|
|
}
|
2026-01-12 12:08:25 +00:00
|
|
|
|
2026-01-12 14:57:13 +00:00
|
|
|
public static async ValueTask<T> SingleAsync<T>(
|
|
|
|
|
this IAsyncEnumerable<T> source,
|
2026-01-13 14:24:36 +00:00
|
|
|
Func<T, bool>? predicate = null
|
2026-01-12 14:57:13 +00:00
|
|
|
)
|
|
|
|
|
{
|
2026-01-13 14:24:36 +00:00
|
|
|
IAsyncEnumerator<T> enumerator;
|
|
|
|
|
if (predicate is null)
|
|
|
|
|
{
|
|
|
|
|
enumerator = source.GetAsyncEnumerator();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
enumerator = source.WhereAsync(predicate).GetAsyncEnumerator();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 14:57:13 +00:00
|
|
|
if (!await enumerator.MoveNextAsync())
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("The source sequence is empty.");
|
|
|
|
|
}
|
2026-01-12 15:01:29 +00:00
|
|
|
var value = enumerator.Current;
|
2026-01-12 14:57:13 +00:00
|
|
|
if (await enumerator.MoveNextAsync())
|
|
|
|
|
{
|
2026-01-12 15:01:29 +00:00
|
|
|
throw new InvalidOperationException(
|
|
|
|
|
"The source sequence contains more than one element."
|
|
|
|
|
);
|
2026-01-12 14:57:13 +00:00
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
public static async ValueTask<T> FirstAsync<T>(this IAsyncEnumerable<T> source)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var item in source)
|
2026-01-07 14:47:20 +00:00
|
|
|
{
|
2026-01-12 14:14:46 +00:00
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
throw new InvalidOperationException("The source sequence is empty.");
|
|
|
|
|
}
|
2026-01-07 14:47:20 +00:00
|
|
|
|
2026-01-12 14:14:46 +00:00
|
|
|
public static async ValueTask<T?> FirstOrDefaultAsync<T>(this IAsyncEnumerable<T> source)
|
|
|
|
|
{
|
|
|
|
|
await foreach (var item in source)
|
|
|
|
|
{
|
|
|
|
|
return item;
|
2026-01-08 09:14:46 +00:00
|
|
|
}
|
2026-01-12 14:14:46 +00:00
|
|
|
|
|
|
|
|
return default;
|
2026-01-07 14:47:20 +00:00
|
|
|
}
|
|
|
|
|
}
|