using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Kyoo.Utils
{
///
/// A set of extensions class for enumerable.
///
public static class EnumerableExtensions
{
///
/// A Select where the index of the item can be used.
///
/// The IEnumerable to map. If self is null, an empty list is returned
/// The function that will map each items
/// The type of items in
/// The type of items in the returned list
/// The list mapped.
/// The list or the mapper can't be null
[LinqTunnel]
public static IEnumerable Map([NotNull] this IEnumerable self,
[NotNull] Func mapper)
{
if (self == null)
throw new ArgumentNullException(nameof(self));
if (mapper == null)
throw new ArgumentNullException(nameof(mapper));
static IEnumerable Generator(IEnumerable self, Func mapper)
{
using IEnumerator enumerator = self.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
{
yield return mapper(enumerator.Current, index);
index++;
}
}
return Generator(self, mapper);
}
///
/// A map where the mapping function is asynchronous.
/// Note: might interest you.
///
/// The IEnumerable to map.
/// The asynchronous function that will map each items
/// The type of items in
/// The type of items in the returned list
/// The list mapped as an AsyncEnumerable
/// The list or the mapper can't be null
[LinqTunnel]
public static IAsyncEnumerable MapAsync([NotNull] this IEnumerable self,
[NotNull] Func> mapper)
{
if (self == null)
throw new ArgumentNullException(nameof(self));
if (mapper == null)
throw new ArgumentNullException(nameof(mapper));
static async IAsyncEnumerable Generator(IEnumerable self, Func> mapper)
{
using IEnumerator enumerator = self.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
{
yield return await mapper(enumerator.Current, index);
index++;
}
}
return Generator(self, mapper);
}
///
/// An asynchronous version of Select.
///
/// The IEnumerable to map
/// The asynchronous function that will map each items
/// The type of items in
/// The type of items in the returned list
/// The list mapped as an AsyncEnumerable
/// The list or the mapper can't be null
[LinqTunnel]
public static IAsyncEnumerable SelectAsync([NotNull] this IEnumerable self,
[NotNull] Func> mapper)
{
if (self == null)
throw new ArgumentNullException(nameof(self));
if (mapper == null)
throw new ArgumentNullException(nameof(mapper));
static async IAsyncEnumerable Generator(IEnumerable self, Func> mapper)
{
using IEnumerator enumerator = self.GetEnumerator();
while (enumerator.MoveNext())
yield return await mapper(enumerator.Current);
}
return Generator(self, mapper);
}
///
/// Convert an AsyncEnumerable to a List by waiting for every item.
///
/// The async list
/// The type of items in the async list and in the returned list.
/// A task that will return a simple list
/// The list can't be null
[LinqTunnel]
public static Task> ToListAsync([NotNull] this IAsyncEnumerable self)
{
if (self == null)
throw new ArgumentNullException(nameof(self));
static async Task> ToList(IAsyncEnumerable self)
{
List ret = new();
await foreach (T i in self)
ret.Add(i);
return ret;
}
return ToList(self);
}
///
/// If the enumerable is empty, execute an action.
///
/// The enumerable to check
/// The action to execute is the list is empty
/// The type of items inside the list
/// The iterable and the action can't be null.
/// The iterator proxied, there is no dual iterations.
[LinqTunnel]
public static IEnumerable IfEmpty([NotNull] this IEnumerable self, [NotNull] Action action)
{
if (self == null)
throw new ArgumentNullException(nameof(self));
if (action == null)
throw new ArgumentNullException(nameof(action));
static IEnumerable Generator(IEnumerable self, Action action)
{
using IEnumerator enumerator = self.GetEnumerator();
if (!enumerator.MoveNext())
{
action();
yield break;
}
do
{
yield return enumerator.Current;
}
while (enumerator.MoveNext());
}
return Generator(self, action);
}
///
/// A foreach used as a function with a little specificity: the list can be null.
///
/// The list to enumerate. If this is null, the function result in a no-op
/// The action to execute for each arguments
/// The type of items in the list
public static void ForEach([CanBeNull] this IEnumerable self, Action action)
{
if (self == null)
return;
foreach (T i in self)
action(i);
}
///
/// A foreach used as a function with a little specificity: the list can be null.
///
/// The list to enumerate. If this is null, the function result in a no-op
/// The action to execute for each arguments
public static void ForEach([CanBeNull] this IEnumerable self, Action