mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-16 03:50:11 +00:00
move to underunity
This commit is contained in:
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public interface IUniTaskAsyncEnumerable<out T>
|
||||
{
|
||||
IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface IUniTaskAsyncEnumerator<out T> : IUniTaskAsyncDisposable
|
||||
{
|
||||
T Current { get; }
|
||||
UniTask<bool> MoveNextAsync();
|
||||
}
|
||||
|
||||
public interface IUniTaskAsyncDisposable
|
||||
{
|
||||
UniTask DisposeAsync();
|
||||
}
|
||||
|
||||
public interface IUniTaskOrderedAsyncEnumerable<TElement> : IUniTaskAsyncEnumerable<TElement>
|
||||
{
|
||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
|
||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
|
||||
IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
|
||||
}
|
||||
|
||||
//public interface IUniTaskAsyncGrouping<out TKey, out TElement> : IUniTaskAsyncEnumerable<TElement>
|
||||
//{
|
||||
// TKey Key { get; }
|
||||
//}
|
||||
|
||||
public static class UniTaskAsyncEnumerableExtensions
|
||||
{
|
||||
public static UniTaskCancelableAsyncEnumerable<T> WithCancellation<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UniTaskCancelableAsyncEnumerable<T>(source, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly struct UniTaskCancelableAsyncEnumerable<T>
|
||||
{
|
||||
private readonly IUniTaskAsyncEnumerable<T> enumerable;
|
||||
private readonly CancellationToken cancellationToken;
|
||||
|
||||
internal UniTaskCancelableAsyncEnumerable(IUniTaskAsyncEnumerable<T> enumerable, CancellationToken cancellationToken)
|
||||
{
|
||||
this.enumerable = enumerable;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Enumerator GetAsyncEnumerator()
|
||||
{
|
||||
return new Enumerator(enumerable.GetAsyncEnumerator(cancellationToken));
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly struct Enumerator
|
||||
{
|
||||
private readonly IUniTaskAsyncEnumerator<T> enumerator;
|
||||
|
||||
internal Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public T Current => enumerator.Current;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
return enumerator.MoveNextAsync();
|
||||
}
|
||||
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> AggregateAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TAccumulate> AggregateAsync<TSource, TAccumulate>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> AggregateAsync<TSource, TAccumulate, TResult>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(resultSelector));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> AggregateAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, UniTask<TSource>> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TAccumulate> AggregateAwaitAsync<TSource, TAccumulate>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, UniTask<TAccumulate>> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> AggregateAwaitAsync<TSource, TAccumulate, TResult>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, UniTask<TAccumulate>> accumulator, Func<TAccumulate, UniTask<TResult>> resultSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(resultSelector));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> AggregateAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, CancellationToken, UniTask<TSource>> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TAccumulate> AggregateAwaitWithCancellationAsync<TSource, TAccumulate>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, CancellationToken, UniTask<TAccumulate>> accumulator, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> AggregateAwaitWithCancellationAsync<TSource, TAccumulate, TResult>(this IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, CancellationToken, UniTask<TAccumulate>> accumulator, Func<TAccumulate, CancellationToken, UniTask<TResult>> resultSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(accumulator));
|
||||
Error.ThrowArgumentNullException(accumulator, nameof(resultSelector));
|
||||
|
||||
return Aggregate.InvokeAsync(source, seed, accumulator, resultSelector, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Aggregate
|
||||
{
|
||||
internal static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value;
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = accumulator(value, e.Current);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TAccumulate> InvokeAsync<TSource, TAccumulate>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = accumulator(value, e.Current);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TResult> InvokeAsync<TSource, TAccumulate, TResult>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = accumulator(value, e.Current);
|
||||
}
|
||||
return resultSelector(value);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// with async
|
||||
|
||||
internal static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, UniTask<TSource>> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value;
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TAccumulate> InvokeAsync<TSource, TAccumulate>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, UniTask<TAccumulate>> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TResult> InvokeAsync<TSource, TAccumulate, TResult>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, UniTask<TAccumulate>> accumulator, Func<TAccumulate, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current);
|
||||
}
|
||||
return await resultSelector(value);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// with cancellation
|
||||
|
||||
internal static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TSource, CancellationToken, UniTask<TSource>> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value;
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current, cancellationToken);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TAccumulate> InvokeAsync<TSource, TAccumulate>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, CancellationToken, UniTask<TAccumulate>> accumulator, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current, cancellationToken);
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<TResult> InvokeAsync<TSource, TAccumulate, TResult>(IUniTaskAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, CancellationToken, UniTask<TAccumulate>> accumulator, Func<TAccumulate, CancellationToken, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TAccumulate value = seed;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await accumulator(value, e.Current, cancellationToken);
|
||||
}
|
||||
return await resultSelector(value, cancellationToken);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Boolean> AllAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return All.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> AllAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return All.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> AllAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return All.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class All
|
||||
{
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (!predicate(e.Current))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (!await predicate(e.Current))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (!await predicate(e.Current, cancellationToken))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Boolean> AnyAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Any.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> AnyAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Any.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> AnyAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Any.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> AnyAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Any.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Any
|
||||
{
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (predicate(e.Current))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current, cancellationToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Append<TSource>(this IUniTaskAsyncEnumerable<TSource> source, TSource element)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new AppendPrepend<TSource>(source, element, true);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Prepend<TSource>(this IUniTaskAsyncEnumerable<TSource> source, TSource element)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new AppendPrepend<TSource>(source, element, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AppendPrepend<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly TSource element;
|
||||
readonly bool append; // or prepend
|
||||
|
||||
public AppendPrepend(IUniTaskAsyncEnumerable<TSource> source, TSource element, bool append)
|
||||
{
|
||||
this.source = source;
|
||||
this.element = element;
|
||||
this.append = append;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, element, append, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
enum State : byte
|
||||
{
|
||||
None,
|
||||
RequirePrepend,
|
||||
RequireAppend,
|
||||
Completed
|
||||
}
|
||||
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly TSource element;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
State state;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, TSource element, bool append, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.element = element;
|
||||
this.state = append ? State.RequireAppend : State.RequirePrepend;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
if (state == State.RequireAppend)
|
||||
{
|
||||
Current = element;
|
||||
state = State.None;
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
if (state == State.Completed)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCoreDelegate(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.state == State.RequireAppend)
|
||||
{
|
||||
self.state = State.Completed;
|
||||
self.Current = self.element;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.state = State.Completed;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> AsUniTaskAsyncEnumerable<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public abstract class MoveNextSource : IUniTaskSource<bool>
|
||||
{
|
||||
protected UniTaskCompletionSourceCore<bool> completionSource;
|
||||
|
||||
public bool GetResult(short token)
|
||||
{
|
||||
return completionSource.GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return completionSource.GetStatus(token);
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
completionSource.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return completionSource.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
completionSource.GetResult(token);
|
||||
}
|
||||
|
||||
protected bool TryGetResult<T>(UniTask<T>.Awaiter awaiter, out T result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = awaiter.GetResult();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool TryGetResult(UniTask.Awaiter awaiter)
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter.GetResult();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AsyncEnumeratorBase<TSource, TResult> : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
protected CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter sourceMoveNext;
|
||||
|
||||
public AsyncEnumeratorBase(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
// abstract
|
||||
|
||||
/// <summary>
|
||||
/// If return value is false, continue source.MoveNext.
|
||||
/// </summary>
|
||||
protected abstract bool TryMoveNextCore(bool sourceHasCurrent, out bool result);
|
||||
|
||||
// Util
|
||||
protected TSource SourceCurrent => enumerator.Current;
|
||||
|
||||
// IUniTaskAsyncEnumerator<T>
|
||||
|
||||
public TResult Current { get; protected set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
if (!OnFirstIteration())
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
protected virtual bool OnFirstIteration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void SourceMoveNext()
|
||||
{
|
||||
CONTINUE:
|
||||
sourceMoveNext = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (sourceMoveNext.IsCompleted)
|
||||
{
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
if (!TryMoveNextCore(sourceMoveNext.GetResult(), out result))
|
||||
{
|
||||
goto CONTINUE;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completionSource.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceMoveNext.SourceOnCompleted(moveNextCallbackDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCallBack(object state)
|
||||
{
|
||||
var self = (AsyncEnumeratorBase<TSource, TResult>)state;
|
||||
bool result;
|
||||
try
|
||||
{
|
||||
if (!self.TryMoveNextCore(self.sourceMoveNext.GetResult(), out result))
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
// if require additional resource to dispose, override and call base.DisposeAsync.
|
||||
public virtual UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TAwait> : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> moveNextCallbackDelegate = MoveNextCallBack;
|
||||
static readonly Action<object> setCurrentCallbackDelegate = SetCurrentCallBack;
|
||||
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
protected CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter sourceMoveNext;
|
||||
|
||||
UniTask<TAwait>.Awaiter resultAwaiter;
|
||||
|
||||
public AsyncEnumeratorAwaitSelectorBase(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
// abstract
|
||||
|
||||
protected abstract UniTask<TAwait> TransformAsync(TSource sourceCurrent);
|
||||
protected abstract bool TrySetCurrentCore(TAwait awaitResult, out bool terminateIteration);
|
||||
|
||||
// Util
|
||||
protected TSource SourceCurrent { get; private set; }
|
||||
|
||||
protected (bool waitCallback, bool requireNextIteration) ActionCompleted(bool trySetCurrentResult, out bool moveNextResult)
|
||||
{
|
||||
if (trySetCurrentResult)
|
||||
{
|
||||
moveNextResult = true;
|
||||
return (false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveNextResult = default;
|
||||
return (false, true);
|
||||
}
|
||||
}
|
||||
protected (bool waitCallback, bool requireNextIteration) WaitAwaitCallback(out bool moveNextResult) { moveNextResult = default; return (true, false); }
|
||||
protected (bool waitCallback, bool requireNextIteration) IterateFinished(out bool moveNextResult) { moveNextResult = false; return (false, false); }
|
||||
|
||||
// IUniTaskAsyncEnumerator<T>
|
||||
|
||||
public TResult Current { get; protected set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
protected void SourceMoveNext()
|
||||
{
|
||||
CONTINUE:
|
||||
sourceMoveNext = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (sourceMoveNext.IsCompleted)
|
||||
{
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
(bool waitCallback, bool requireNextIteration) = TryMoveNextCore(sourceMoveNext.GetResult(), out result);
|
||||
|
||||
if (waitCallback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (requireNextIteration)
|
||||
{
|
||||
goto CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceMoveNext.SourceOnCompleted(moveNextCallbackDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
(bool waitCallback, bool requireNextIteration) TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
SourceCurrent = enumerator.Current;
|
||||
var task = TransformAsync(SourceCurrent);
|
||||
if (UnwarapTask(task, out var taskResult))
|
||||
{
|
||||
var currentResult = TrySetCurrentCore(taskResult, out var terminateIteration);
|
||||
if (terminateIteration)
|
||||
{
|
||||
return IterateFinished(out result);
|
||||
}
|
||||
|
||||
return ActionCompleted(currentResult, out result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WaitAwaitCallback(out result);
|
||||
}
|
||||
}
|
||||
|
||||
return IterateFinished(out result);
|
||||
}
|
||||
|
||||
protected bool UnwarapTask(UniTask<TAwait> taskResult, out TAwait result)
|
||||
{
|
||||
resultAwaiter = taskResult.GetAwaiter();
|
||||
|
||||
if (resultAwaiter.IsCompleted)
|
||||
{
|
||||
result = resultAwaiter.GetResult();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultAwaiter.SourceOnCompleted(setCurrentCallbackDelegate, this);
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCallBack(object state)
|
||||
{
|
||||
var self = (AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TAwait>)state;
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
(bool waitCallback, bool requireNextIteration) = self.TryMoveNextCore(self.sourceMoveNext.GetResult(), out result);
|
||||
|
||||
if (waitCallback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (requireNextIteration)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetCurrentCallBack(object state)
|
||||
{
|
||||
var self = (AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TAwait>)state;
|
||||
|
||||
bool doneSetCurrent;
|
||||
bool terminateIteration;
|
||||
try
|
||||
{
|
||||
var result = self.resultAwaiter.GetResult();
|
||||
doneSetCurrent = self.TrySetCurrentCore(result, out terminateIteration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (doneSetCurrent)
|
||||
{
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (terminateIteration)
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if require additional resource to dispose, override and call base.DisposeAsync.
|
||||
public virtual UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,237 +0,0 @@
|
||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#
|
||||
var types = new[]
|
||||
{
|
||||
(typeof(int), "double"),
|
||||
(typeof(long), "double"),
|
||||
(typeof(float),"float"),
|
||||
(typeof(double),"double"),
|
||||
(typeof(decimal),"decimal"),
|
||||
|
||||
(typeof(int?),"double?"),
|
||||
(typeof(long?),"double?"),
|
||||
(typeof(float?),"float?"),
|
||||
(typeof(double?),"double?"),
|
||||
(typeof(decimal?),"decimal?"),
|
||||
};
|
||||
|
||||
Func<Type, bool> IsNullable = x => x.IsGenericType;
|
||||
Func<Type, Type> ElementType = x => IsNullable(x) ? x.GetGenericArguments()[0] : x;
|
||||
Func<Type, string> TypeName = x => IsNullable(x) ? x.GetGenericArguments()[0].Name + "?" : x.Name;
|
||||
Func<Type, string> WithSuffix = x => IsNullable(x) ? ".GetValueOrDefault()" : "";
|
||||
Func<Type, string> CalcResult = x => { var e = ElementType(x); return (e == typeof(int) || e == typeof(long)) ? "(double)sum / count" : (e == typeof(float)) ? "(float)(sum / count)" : "sum / count"; };
|
||||
#>
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
<# foreach(var (t, ret) in types) { #>
|
||||
public static UniTask<<#= ret #>> AverageAsync(this IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Average.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= ret #>> AverageAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Average.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= ret #>> AverageAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Average.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= ret #>> AverageAwaitCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Average.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
|
||||
internal static class Average
|
||||
{
|
||||
<# foreach(var (t, ret) in types) { #>
|
||||
public static async UniTask<<#= ret #>> InvokeAsync(IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
<#= TypeName(t) #> sum = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
<# if (IsNullable(t)) { #>
|
||||
var v = e.Current;
|
||||
if (v.HasValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
sum += v.Value;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
<# } else { #>
|
||||
checked
|
||||
{
|
||||
sum += e.Current;
|
||||
count++;
|
||||
}
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return <#= CalcResult(t) #>;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= ret #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
<#= TypeName(t) #> sum = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
<# if (IsNullable(t)) { #>
|
||||
var v = selector(e.Current);
|
||||
if (v.HasValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
sum += v.Value;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
<# } else { #>
|
||||
checked
|
||||
{
|
||||
sum += selector(e.Current);
|
||||
count++;
|
||||
}
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return <#= CalcResult(t) #>;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= ret #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
<#= TypeName(t) #> sum = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
<# if (IsNullable(t)) { #>
|
||||
var v = await selector(e.Current);
|
||||
if (v.HasValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
sum += v.Value;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
<# } else { #>
|
||||
checked
|
||||
{
|
||||
sum += await selector(e.Current);
|
||||
count++;
|
||||
}
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return <#= CalcResult(t) #>;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= ret #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
<#= TypeName(t) #> sum = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
<# if (IsNullable(t)) { #>
|
||||
var v = await selector(e.Current, cancellationToken);
|
||||
if (v.HasValue)
|
||||
{
|
||||
checked
|
||||
{
|
||||
sum += v.Value;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
<# } else { #>
|
||||
checked
|
||||
{
|
||||
sum += await selector(e.Current, cancellationToken);
|
||||
count++;
|
||||
}
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return <#= CalcResult(t) #>;
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<IList<TSource>> Buffer<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
if (count <= 0) throw Error.ArgumentOutOfRange(nameof(count));
|
||||
|
||||
return new Buffer<TSource>(source, count);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IList<TSource>> Buffer<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count, Int32 skip)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
if (count <= 0) throw Error.ArgumentOutOfRange(nameof(count));
|
||||
if (skip <= 0) throw Error.ArgumentOutOfRange(nameof(skip));
|
||||
|
||||
return new BufferSkip<TSource>(source, count, skip);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Buffer<TSource> : IUniTaskAsyncEnumerable<IList<TSource>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
|
||||
public Buffer(IUniTaskAsyncEnumerable<TSource> source, int count)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<IList<TSource>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<IList<TSource>>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
|
||||
bool completed;
|
||||
List<TSource> buffer;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public IList<TSource> Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
buffer = new List<TSource>(count);
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
if (buffer != null && buffer.Count > 0)
|
||||
{
|
||||
var ret = buffer;
|
||||
buffer = null;
|
||||
Current = ret;
|
||||
completionSource.TrySetResult(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.buffer.Add(self.enumerator.Current);
|
||||
|
||||
if (self.buffer.Count == self.count)
|
||||
{
|
||||
self.Current = self.buffer;
|
||||
self.buffer = new List<TSource>(self.count);
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completed = true;
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BufferSkip<TSource> : IUniTaskAsyncEnumerable<IList<TSource>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
readonly int skip;
|
||||
|
||||
public BufferSkip(IUniTaskAsyncEnumerable<TSource> source, int count, int skip)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<IList<TSource>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, skip, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<IList<TSource>>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
readonly int skip;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
|
||||
bool completed;
|
||||
Queue<List<TSource>> buffers;
|
||||
int index = 0;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, int skip, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
this.skip = skip;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public IList<TSource> Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
buffers = new Queue<List<TSource>>();
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
if (buffers.Count > 0)
|
||||
{
|
||||
Current = buffers.Dequeue();
|
||||
completionSource.TrySetResult(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (self.index++ % self.skip == 0)
|
||||
{
|
||||
self.buffers.Enqueue(new List<TSource>(self.count));
|
||||
}
|
||||
|
||||
var item = self.enumerator.Current;
|
||||
foreach (var buffer in self.buffers)
|
||||
{
|
||||
buffer.Add(item);
|
||||
}
|
||||
|
||||
if (self.buffers.Count > 0 && self.buffers.Peek().Count == self.count)
|
||||
{
|
||||
self.Current = self.buffers.Dequeue();
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completed = true;
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TResult> Cast<TResult>(this IUniTaskAsyncEnumerable<Object> source)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new Cast<TResult>(source);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Cast<TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<object> source;
|
||||
|
||||
public Cast(IUniTaskAsyncEnumerable<object> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<object, TResult>
|
||||
{
|
||||
public Enumerator(IUniTaskAsyncEnumerable<object> source, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
Current = (TResult)SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Concat<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return new Concat<TSource>(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Concat<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
|
||||
public Concat(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
enum IteratingState
|
||||
{
|
||||
IteratingFirst,
|
||||
IteratingSecond,
|
||||
Complete
|
||||
}
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IteratingState iteratingState;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, CancellationToken cancellationToken)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.iteratingState = IteratingState.IteratingFirst;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (iteratingState == IteratingState.Complete) return CompletedTasks.False;
|
||||
|
||||
completionSource.Reset();
|
||||
StartIterate();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void StartIterate()
|
||||
{
|
||||
if (enumerator == null)
|
||||
{
|
||||
if (iteratingState == IteratingState.IteratingFirst)
|
||||
{
|
||||
enumerator = first.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
else if (iteratingState == IteratingState.IteratingSecond)
|
||||
{
|
||||
enumerator = second.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCoreDelegate(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.iteratingState == IteratingState.IteratingFirst)
|
||||
{
|
||||
self.RunSecondAfterDisposeAsync().Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
self.iteratingState = IteratingState.Complete;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunSecondAfterDisposeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await enumerator.DisposeAsync();
|
||||
enumerator = null;
|
||||
awaiter = default;
|
||||
iteratingState = IteratingState.IteratingSecond;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
|
||||
StartIterate();
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Boolean> ContainsAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, TSource value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return ContainsAsync(source, value, EqualityComparer<TSource>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> ContainsAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return Contains.InvokeAsync(source, value, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Contains
|
||||
{
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (comparer.Equals(value, e.Current))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Int32> CountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Count.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Int32> CountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Count.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Int32> CountAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Count.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Int32> CountAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Count.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Count
|
||||
{
|
||||
internal static async UniTask<int> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<int> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (predicate(e.Current))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<int> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<int> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current, cancellationToken))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> DefaultIfEmpty<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new DefaultIfEmpty<TSource>(source, default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DefaultIfEmpty<TSource>(this IUniTaskAsyncEnumerable<TSource> source, TSource defaultValue)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new DefaultIfEmpty<TSource>(source, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DefaultIfEmpty<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly TSource defaultValue;
|
||||
|
||||
public DefaultIfEmpty(IUniTaskAsyncEnumerable<TSource> source, TSource defaultValue)
|
||||
{
|
||||
this.source = source;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, defaultValue, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
enum IteratingState : byte
|
||||
{
|
||||
Empty,
|
||||
Iterating,
|
||||
Completed
|
||||
}
|
||||
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly TSource defaultValue;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IteratingState iteratingState;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, TSource defaultValue, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.defaultValue = defaultValue;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
this.iteratingState = IteratingState.Empty;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (iteratingState == IteratingState.Completed)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.iteratingState = IteratingState.Iterating;
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.iteratingState == IteratingState.Empty)
|
||||
{
|
||||
self.iteratingState = IteratingState.Completed;
|
||||
|
||||
self.Current = self.defaultValue;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
return Distinct(source, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new Distinct<TSource>(source, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
return Distinct(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new Distinct<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
return DistinctAwait(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctAwait<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
return DistinctAwaitWithCancellation(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctAwaitCancellation<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Distinct<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
|
||||
public Distinct(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly HashSet<TSource> set;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.set = new HashSet<TSource>(comparer);
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
if (set.Add(v))
|
||||
{
|
||||
Current = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Distinct<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public Distinct(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly HashSet<TKey> set;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.set = new HashSet<TKey>(comparer);
|
||||
this.keySelector = keySelector;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
if (set.Add(keySelector(v)))
|
||||
{
|
||||
Current = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctAwait<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public DistinctAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
|
||||
{
|
||||
readonly HashSet<TKey> set;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.set = new HashSet<TKey>(comparer);
|
||||
this.keySelector = keySelector;
|
||||
}
|
||||
|
||||
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return keySelector(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TKey awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (set.Add(awaitResult))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctAwaitCancellation<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public DistinctAwaitCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
|
||||
{
|
||||
readonly HashSet<TKey> set;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.set = new HashSet<TKey>(comparer);
|
||||
this.keySelector = keySelector;
|
||||
}
|
||||
|
||||
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return keySelector(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TKey awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (set.Add(awaitResult))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChanged<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
return DistinctUntilChanged(source, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChanged<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctUntilChanged<TSource>(source, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
return DistinctUntilChanged(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctUntilChanged<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChangedAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
return DistinctUntilChangedAwait(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChangedAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctUntilChangedAwait<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChangedAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
return DistinctUntilChangedAwaitWithCancellation(source, keySelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> DistinctUntilChangedAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new DistinctUntilChangedAwaitCancellation<TSource, TKey>(source, keySelector, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctUntilChanged<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
|
||||
public DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
TSource prev;
|
||||
bool first;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
this.first = true;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
if (first || !comparer.Equals(prev, v))
|
||||
{
|
||||
first = false;
|
||||
Current = prev = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctUntilChanged<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
TKey prev;
|
||||
bool first;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
this.keySelector = keySelector;
|
||||
this.first = true;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
var key = keySelector(v);
|
||||
if (first || !comparer.Equals(prev, key))
|
||||
{
|
||||
first = false;
|
||||
prev = key;
|
||||
Current = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctUntilChangedAwait<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public DistinctUntilChangedAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
|
||||
{
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
TKey prev;
|
||||
bool first;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
this.keySelector = keySelector;
|
||||
this.first = true;
|
||||
}
|
||||
|
||||
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return keySelector(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TKey key, out bool terminateIteration)
|
||||
{
|
||||
if (first || !comparer.Equals(prev, key))
|
||||
{
|
||||
first = false;
|
||||
prev = key;
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistinctUntilChangedAwaitCancellation<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public DistinctUntilChangedAwaitCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
|
||||
{
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
TKey prev;
|
||||
bool first;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
this.keySelector = keySelector;
|
||||
this.first = true;
|
||||
}
|
||||
|
||||
protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return keySelector(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TKey key, out bool terminateIteration)
|
||||
{
|
||||
if (first || !comparer.Equals(prev, key))
|
||||
{
|
||||
first = false;
|
||||
prev = key;
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Do<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
return source.Do(onNext, null, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Do<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
return source.Do(onNext, onError, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Do<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
return source.Do(onNext, null, onCompleted);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Do<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
return new Do<TSource>(source, onNext, onError, onCompleted);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Do<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(observer, nameof(observer));
|
||||
|
||||
return source.Do(observer.OnNext, observer.OnError, observer.OnCompleted); // alloc delegate.
|
||||
}
|
||||
|
||||
// not yet impl.
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Func<Exception, UniTask> onError)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Func<UniTask> onCompleted)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Func<Exception, UniTask> onError, Func<UniTask> onCompleted)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Func<Exception, CancellationToken, UniTask> onError)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Func<CancellationToken, UniTask> onCompleted)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public static IUniTaskAsyncEnumerable<TSource> DoAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Func<Exception, CancellationToken, UniTask> onError, Func<CancellationToken, UniTask> onCompleted)
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
}
|
||||
|
||||
internal sealed class Do<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Action<TSource> onNext;
|
||||
readonly Action<Exception> onError;
|
||||
readonly Action onCompleted;
|
||||
|
||||
public Do(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
|
||||
{
|
||||
this.source = source;
|
||||
this.onNext = onNext;
|
||||
this.onError = onError;
|
||||
this.onCompleted = onCompleted;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, onNext, onError, onCompleted, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Action<TSource> onNext;
|
||||
readonly Action<Exception> onError;
|
||||
readonly Action onCompleted;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.onNext = onNext;
|
||||
this.onError = onError;
|
||||
this.onCompleted = onCompleted;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
bool isCompleted = false;
|
||||
try
|
||||
{
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
isCompleted = awaiter.IsCompleted;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CallTrySetExceptionAfterNotification(ex);
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
if (isCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void CallTrySetExceptionAfterNotification(Exception ex)
|
||||
{
|
||||
if (onError != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
onError(ex);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
completionSource.TrySetException(ex2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
|
||||
bool TryGetResultWithNotification<T>(UniTask<T>.Awaiter awaiter, out T result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = awaiter.GetResult();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CallTrySetExceptionAfterNotification(ex);
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResultWithNotification(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
var v = self.enumerator.Current;
|
||||
|
||||
if (self.onNext != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.onNext(v);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.CallTrySetExceptionAfterNotification(ex);
|
||||
}
|
||||
}
|
||||
|
||||
self.Current = v;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.onCompleted != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.CallTrySetExceptionAfterNotification(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> ElementAtAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, int index, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return ElementAt.InvokeAsync(source, index, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> ElementAtOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, int index, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return ElementAt.InvokeAsync(source, index, cancellationToken, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ElementAt
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, int index, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
int i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (i++ == index)
|
||||
{
|
||||
return e.Current;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.ArgumentOutOfRange(nameof(index));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> Empty<T>()
|
||||
{
|
||||
return Cysharp.Threading.Tasks.Linq.Empty<T>.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Empty<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
public static readonly IUniTaskAsyncEnumerable<T> Instance = new Empty<T>();
|
||||
|
||||
Empty()
|
||||
{
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Enumerator.Instance;
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
public static readonly IUniTaskAsyncEnumerator<T> Instance = new Enumerator();
|
||||
|
||||
Enumerator()
|
||||
{
|
||||
}
|
||||
|
||||
public T Current => default;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Except<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return new Except<TSource>(first, second, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Except<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new Except<TSource>(first, second, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Except<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
|
||||
public Except(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
static Action<object> HashSetAsyncCoreDelegate = HashSetAsyncCore;
|
||||
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
|
||||
HashSet<TSource> set;
|
||||
UniTask<HashSet<TSource>>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(first, cancellationToken)
|
||||
{
|
||||
this.second = second;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
protected override bool OnFirstIteration()
|
||||
{
|
||||
if (set != null) return false;
|
||||
|
||||
awaiter = second.ToHashSetAsync(cancellationToken).GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
set = awaiter.GetResult();
|
||||
SourceMoveNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(HashSetAsyncCoreDelegate, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HashSetAsyncCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
self.set = result;
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
if (set.Add(v))
|
||||
{
|
||||
Current = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> FirstAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return First.InvokeAsync(source, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return First.InvokeAsync(source, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstOrDefaultAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> FirstOrDefaultAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return First.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class First
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
return e.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (predicate(v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v, cancellationToken))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask ForEachAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAsync(source, action, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ForEachAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource, Int32> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAsync(source, action, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ForEachAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAwaitAsync(source, action, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ForEachAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAwaitAsync(source, action, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ForEachAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAwaitWithCancellationAsync(source, action, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ForEachAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask> action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ForEach.InvokeAwaitWithCancellationAsync(source, action, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ForEach
|
||||
{
|
||||
public static async UniTask InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
action(e.Current);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Action<TSource, Int32> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
action(e.Current, checked(index++));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask InvokeAwaitAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
await action(e.Current);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask InvokeAwaitAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
await action(e.Current, checked(index++));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask InvokeAwaitWithCancellationAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
await action(e.Current, cancellationToken);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask InvokeAwaitWithCancellationAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask> action, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
await action(e.Current, checked(index++), cancellationToken);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,911 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
// Ix-Async returns IGrouping but it is competely waste, use standard IGrouping.
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
return new GroupBy<TSource, TKey, TSource>(source, keySelector, x => x, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupBy<TSource, TKey, TSource>(source, keySelector, x => x, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
return new GroupBy<TSource, TKey, TElement>(source, keySelector, elementSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupBy<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupBy<TSource, TKey, TSource, TResult>(source, keySelector, x => x, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupBy<TSource, TKey, TSource, TResult>(source, keySelector, x => x, resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupBy<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupBy<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
// await
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupByAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
return new GroupByAwait<TSource, TKey, TSource>(source, keySelector, x => UniTask.FromResult(x), EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupByAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwait<TSource, TKey, TSource>(source, keySelector, x => UniTask.FromResult(x), comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupByAwait<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
return new GroupByAwait<TSource, TKey, TElement>(source, keySelector, elementSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupByAwait<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwait<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwait<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TKey, IEnumerable<TSource>, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupByAwait<TSource, TKey, TSource, TResult>(source, keySelector, x => UniTask.FromResult(x), resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwait<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupByAwait<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwait<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TKey, IEnumerable<TSource>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwait<TSource, TKey, TSource, TResult>(source, keySelector, x => UniTask.FromResult(x), resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwait<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwait<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
// with ct
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupByAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TSource>(source, keySelector, (x, _) => UniTask.FromResult(x), EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TSource>> GroupByAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TSource>(source, keySelector, (x, _) => UniTask.FromResult(x), comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupByAwaitWithCancellation<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TElement>(source, keySelector, elementSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>> GroupByAwaitWithCancellation<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwaitWithCancellation<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TKey, IEnumerable<TSource>, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TSource, TResult>(source, keySelector, (x, _) => UniTask.FromResult(x), resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwaitWithCancellation<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwaitWithCancellation<TSource, TKey, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TKey, IEnumerable<TSource>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TSource, TResult>(source, keySelector, (x, _) => UniTask.FromResult(x), resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupByAwaitWithCancellation<TSource, TKey, TElement, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
return new GroupByAwaitWithCancellation<TSource, TKey, TElement, TResult>(source, keySelector, elementSelector, resultSelector, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupBy<TSource, TKey, TElement> : IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly Func<TSource, TElement> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupBy(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly Func<TSource, TElement> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public IGrouping<TKey, TElement> Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
Current = groupEnumerator.Current as IGrouping<TKey, TElement>;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupBy<TSource, TKey, TElement, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly Func<TSource, TElement> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupBy(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TKey> keySelector;
|
||||
readonly Func<TSource, TElement> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
var current = groupEnumerator.Current;
|
||||
Current = resultSelector(current.Key, current);
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupByAwait<TSource, TKey, TElement> : IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, UniTask<TElement>> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupByAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, UniTask<TElement>> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public IGrouping<TKey, TElement> Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAwaitAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
Current = groupEnumerator.Current as IGrouping<TKey, TElement>;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupByAwait<TSource, TKey, TElement, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, UniTask<TElement>> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupByAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
readonly static Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, UniTask<TElement>> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
UniTask<TResult>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAwaitAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
var current = groupEnumerator.Current;
|
||||
|
||||
awaiter = resultSelector(current.Key, current).GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(ResultSelectCoreDelegate, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupByAwaitWithCancellation<TSource, TKey, TElement> : IUniTaskAsyncEnumerable<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TElement>> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupByAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<IGrouping<TKey, TElement>>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TElement>> elementSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public IGrouping<TKey, TElement> Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAwaitWithCancellationAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
Current = groupEnumerator.Current as IGrouping<TKey, TElement>;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupByAwaitWithCancellation<TSource, TKey, TElement, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TElement>> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupByAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
readonly static Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TElement>> elementSelector;
|
||||
readonly Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IEnumerator<IGrouping<TKey, TElement>> groupEnumerator;
|
||||
UniTask<TResult>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, Func<TKey, IEnumerable<TElement>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.keySelector = keySelector;
|
||||
this.elementSelector = elementSelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (groupEnumerator == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var lookup = await source.ToLookupAwaitWithCancellationAsync(keySelector, elementSelector, comparer, cancellationToken);
|
||||
groupEnumerator = lookup.GetEnumerator();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (groupEnumerator.MoveNext())
|
||||
{
|
||||
var current = groupEnumerator.Current;
|
||||
|
||||
awaiter = resultSelector(current.Key, current, cancellationToken).GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(ResultSelectCoreDelegate, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (groupEnumerator != null)
|
||||
{
|
||||
groupEnumerator.Dispose();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,606 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new GroupJoin<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new GroupJoin<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoinAwait<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new GroupJoinAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoinAwait<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new GroupJoinAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new GroupJoinWithCancellationAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> GroupJoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new GroupJoinWithCancellationAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal sealed class GroupJoin<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, TKey> outerKeySelector;
|
||||
readonly Func<TInner, TKey> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupJoin(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, TKey> outerKeySelector;
|
||||
readonly Func<TInner, TKey> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAsync(innerKeySelector, comparer, cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
var outer = self.enumerator.Current;
|
||||
var key = self.outerKeySelector(outer);
|
||||
var values = self.lookup[key];
|
||||
|
||||
self.Current = self.resultSelector(outer, values);
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupJoinAwait<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupJoinAwait(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
readonly static Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
readonly static Action<object> OuterKeySelectCoreDelegate = OuterKeySelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
TOuter outerValue;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
UniTask<TKey>.Awaiter outerKeyAwaiter;
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAwaitAsync(innerKeySelector, comparer, cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
self.outerValue = self.enumerator.Current;
|
||||
self.outerKeyAwaiter = self.outerKeySelector(self.outerValue).GetAwaiter();
|
||||
if (self.outerKeyAwaiter.IsCompleted)
|
||||
{
|
||||
OuterKeySelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.outerKeyAwaiter.SourceOnCompleted(OuterKeySelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void OuterKeySelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.outerKeyAwaiter, out var result))
|
||||
{
|
||||
try
|
||||
{
|
||||
var values = self.lookup[result];
|
||||
self.resultAwaiter = self.resultSelector(self.outerValue, values).GetAwaiter();
|
||||
if (self.resultAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GroupJoinWithCancellationAwait<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public GroupJoinWithCancellationAwait(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
readonly static Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
readonly static Action<object> OuterKeySelectCoreDelegate = OuterKeySelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
TOuter outerValue;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
UniTask<TKey>.Awaiter outerKeyAwaiter;
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, IEnumerable<TInner>, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateLookup().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateLookup()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAwaitWithCancellationAsync(innerKeySelector, comparer, cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
self.outerValue = self.enumerator.Current;
|
||||
self.outerKeyAwaiter = self.outerKeySelector(self.outerValue, self.cancellationToken).GetAwaiter();
|
||||
if (self.outerKeyAwaiter.IsCompleted)
|
||||
{
|
||||
OuterKeySelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.outerKeyAwaiter.SourceOnCompleted(OuterKeySelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void OuterKeySelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.outerKeyAwaiter, out var result))
|
||||
{
|
||||
try
|
||||
{
|
||||
var values = self.lookup[result];
|
||||
self.resultAwaiter = self.resultSelector(self.outerValue, values, self.cancellationToken).GetAwaiter();
|
||||
if (self.resultAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Intersect<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return new Intersect<TSource>(first, second, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Intersect<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new Intersect<TSource>(first, second, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Intersect<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
|
||||
public Intersect(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
static Action<object> HashSetAsyncCoreDelegate = HashSetAsyncCore;
|
||||
|
||||
readonly IEqualityComparer<TSource> comparer;
|
||||
readonly IUniTaskAsyncEnumerable<TSource> second;
|
||||
|
||||
HashSet<TSource> set;
|
||||
UniTask<HashSet<TSource>>.Awaiter awaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
|
||||
: base(first, cancellationToken)
|
||||
{
|
||||
this.second = second;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
protected override bool OnFirstIteration()
|
||||
{
|
||||
if (set != null) return false;
|
||||
|
||||
awaiter = second.ToHashSetAsync(cancellationToken).GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
set = awaiter.GetResult();
|
||||
SourceMoveNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(HashSetAsyncCoreDelegate, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HashSetAsyncCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
self.set = result;
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
var v = SourceCurrent;
|
||||
|
||||
if (set.Remove(v))
|
||||
{
|
||||
Current = v;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,722 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new Join<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new Join<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> JoinAwait<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new JoinAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> JoinAwait<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new JoinAwait<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> JoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new JoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer<TKey>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> JoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(this IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(outer, nameof(outer));
|
||||
Error.ThrowArgumentNullException(inner, nameof(inner));
|
||||
Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector));
|
||||
Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new JoinAwaitWithCancellation<TOuter, TInner, TKey, TResult>(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Join<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, TKey> outerKeySelector;
|
||||
readonly Func<TInner, TKey> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public Join(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, TKey> outerKeySelector;
|
||||
readonly Func<TInner, TKey> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, TResult> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
TOuter currentOuterValue;
|
||||
IEnumerator<TInner> valueEnumerator;
|
||||
|
||||
bool continueNext;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateInnerHashSet().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateInnerHashSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAsync(innerKeySelector, comparer, cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
if (valueEnumerator.MoveNext())
|
||||
{
|
||||
Current = resultSelector(currentOuterValue, valueEnumerator.Current);
|
||||
goto TRY_SET_RESULT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
valueEnumerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
TRY_SET_RESULT_TRUE:
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.currentOuterValue = self.enumerator.Current;
|
||||
var key = self.outerKeySelector(self.currentOuterValue);
|
||||
self.valueEnumerator = self.lookup[key].GetEnumerator();
|
||||
|
||||
if (self.continueNext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
}
|
||||
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class JoinAwait<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public JoinAwait(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
static readonly Action<object> OuterSelectCoreDelegate = OuterSelectCore;
|
||||
static readonly Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
TOuter currentOuterValue;
|
||||
IEnumerator<TInner> valueEnumerator;
|
||||
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
UniTask<TKey>.Awaiter outerKeyAwaiter;
|
||||
|
||||
bool continueNext;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, UniTask<TKey>> outerKeySelector, Func<TInner, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateInnerHashSet().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateInnerHashSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAwaitAsync(innerKeySelector, comparer, cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
if (valueEnumerator.MoveNext())
|
||||
{
|
||||
resultAwaiter = resultSelector(currentOuterValue, valueEnumerator.Current).GetAwaiter();
|
||||
if (resultAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
valueEnumerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.currentOuterValue = self.enumerator.Current;
|
||||
|
||||
self.outerKeyAwaiter = self.outerKeySelector(self.currentOuterValue).GetAwaiter();
|
||||
|
||||
if (self.outerKeyAwaiter.IsCompleted)
|
||||
{
|
||||
OuterSelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.outerKeyAwaiter.SourceOnCompleted(OuterSelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void OuterSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.outerKeyAwaiter, out var key))
|
||||
{
|
||||
self.valueEnumerator = self.lookup[key].GetEnumerator();
|
||||
|
||||
if (self.continueNext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
}
|
||||
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class JoinAwaitWithCancellation<TOuter, TInner, TKey, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public JoinAwaitWithCancellation(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
static readonly Action<object> OuterSelectCoreDelegate = OuterSelectCore;
|
||||
static readonly Action<object> ResultSelectCoreDelegate = ResultSelectCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TOuter> outer;
|
||||
readonly IUniTaskAsyncEnumerable<TInner> inner;
|
||||
readonly Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector;
|
||||
readonly Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector;
|
||||
readonly Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
readonly IEqualityComparer<TKey> comparer;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
ILookup<TKey, TInner> lookup;
|
||||
IUniTaskAsyncEnumerator<TOuter> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
TOuter currentOuterValue;
|
||||
IEnumerator<TInner> valueEnumerator;
|
||||
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
UniTask<TKey>.Awaiter outerKeyAwaiter;
|
||||
|
||||
bool continueNext;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TOuter> outer, IUniTaskAsyncEnumerable<TInner> inner, Func<TOuter, CancellationToken, UniTask<TKey>> outerKeySelector, Func<TInner, CancellationToken, UniTask<TKey>> innerKeySelector, Func<TOuter, TInner, CancellationToken, UniTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
this.outer = outer;
|
||||
this.inner = inner;
|
||||
this.outerKeySelector = outerKeySelector;
|
||||
this.innerKeySelector = innerKeySelector;
|
||||
this.resultSelector = resultSelector;
|
||||
this.comparer = comparer;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
completionSource.Reset();
|
||||
|
||||
if (lookup == null)
|
||||
{
|
||||
CreateInnerHashSet().Forget();
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateInnerHashSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
lookup = await inner.ToLookupAwaitWithCancellationAsync(innerKeySelector, comparer, cancellationToken: cancellationToken);
|
||||
enumerator = outer.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
SourceMoveNext();
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
if (valueEnumerator.MoveNext())
|
||||
{
|
||||
resultAwaiter = resultSelector(currentOuterValue, valueEnumerator.Current, cancellationToken).GetAwaiter();
|
||||
if (resultAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
valueEnumerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.currentOuterValue = self.enumerator.Current;
|
||||
|
||||
self.outerKeyAwaiter = self.outerKeySelector(self.currentOuterValue, self.cancellationToken).GetAwaiter();
|
||||
|
||||
if (self.outerKeyAwaiter.IsCompleted)
|
||||
{
|
||||
OuterSelectCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.outerKeyAwaiter.SourceOnCompleted(OuterSelectCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void OuterSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.outerKeyAwaiter, out var key))
|
||||
{
|
||||
self.valueEnumerator = self.lookup[key].GetEnumerator();
|
||||
|
||||
if (self.continueNext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (valueEnumerator != null)
|
||||
{
|
||||
valueEnumerator.Dispose();
|
||||
}
|
||||
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> LastAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Last.InvokeAsync(source, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Last.InvokeAsync(source, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastOrDefaultAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> LastOrDefaultAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return Last.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Last
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (predicate(v))
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v))
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v, cancellationToken))
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<long> LongCountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return LongCount.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<long> LongCountAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return LongCount.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<long> LongCountAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return LongCount.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<long> LongCountAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return LongCount.InvokeAsync(source, predicate, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LongCount
|
||||
{
|
||||
internal static async UniTask<long> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<long> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (predicate(e.Current))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<long> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static async UniTask<long> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken)
|
||||
{
|
||||
long count = 0;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
if (await predicate(e.Current, cancellationToken))
|
||||
{
|
||||
checked { count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> MaxAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Max.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MaxAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Max.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MaxAwaitAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Max.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MaxAwaitCancellationAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Max.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static partial class Max
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
TSource value = default;
|
||||
var comparer = Comparer<TSource>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = e.Current;
|
||||
if (comparer.Compare(value, x) < 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = selector(e.Current);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = selector(e.Current);
|
||||
if (comparer.Compare(value, x) < 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current);
|
||||
if (comparer.Compare(value, x) < 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current, cancellationToken);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current, cancellationToken);
|
||||
if (comparer.Compare(value, x) < 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> MinAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Min.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MinAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Min.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MinAwaitAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Min.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<TResult> MinAwaitCancellationAsync<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Min.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static partial class Min
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
TSource value = default;
|
||||
var comparer = Comparer<TSource>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = e.Current;
|
||||
if (comparer.Compare(value, x) > 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = selector(e.Current);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = selector(e.Current);
|
||||
if (comparer.Compare(value, x) > 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current);
|
||||
if (comparer.Compare(value, x) > 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<TResult> InvokeAsync<TSource, TResult>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
TResult value = default;
|
||||
var comparer = Comparer<TResult>.Default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current, cancellationToken);
|
||||
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current, cancellationToken);
|
||||
if (comparer.Compare(value, x) > 0)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,262 +0,0 @@
|
||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#
|
||||
var types = new[]
|
||||
{
|
||||
typeof(int),
|
||||
typeof(long),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(decimal),
|
||||
|
||||
typeof(int?),
|
||||
typeof(long?),
|
||||
typeof(float?),
|
||||
typeof(double?),
|
||||
typeof(decimal?),
|
||||
};
|
||||
|
||||
Func<Type, bool> IsNullable = x => x.IsGenericType;
|
||||
Func<Type, string> TypeName = x => IsNullable(x) ? x.GetGenericArguments()[0].Name + "?" : x.Name;
|
||||
Func<Type, string> WithSuffix = x => IsNullable(x) ? ".GetValueOrDefault()" : "";
|
||||
#>
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
<# foreach(var (minMax, op) in new[]{("Min",">"), ("Max", "<")}) { #>
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
<# foreach(var t in types) { #>
|
||||
public static UniTask<<#= TypeName(t) #>> <#= minMax #>Async(this IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return <#= minMax #>.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> <#= minMax #>Async<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return <#= minMax #>.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> <#= minMax #>AwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return <#= minMax #>.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> <#= minMax #>AwaitCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return <#= minMax #>.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
|
||||
internal static partial class <#= minMax #>
|
||||
{
|
||||
<# foreach(var t in types) { #>
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync(IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> value = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = e.Current;
|
||||
<# if (IsNullable(t)) { #>
|
||||
if(value == null) continue;
|
||||
<# } #>
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
<# if (IsNullable(t)) { #>
|
||||
return default;
|
||||
<# } else { #>
|
||||
throw Error.NoElements();
|
||||
<# } #>
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = e.Current;
|
||||
<# if (IsNullable(t)) { #>
|
||||
if( x == null) continue;
|
||||
<# } #>
|
||||
if (value <#= op #> x)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> value = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = selector(e.Current);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if(value == null) continue;
|
||||
<# } #>
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
<# if (IsNullable(t)) { #>
|
||||
return default;
|
||||
<# } else { #>
|
||||
throw Error.NoElements();
|
||||
<# } #>
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = selector(e.Current);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if( x == null) continue;
|
||||
<# } #>
|
||||
if (value <#= op #> x)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> value = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if(value == null) continue;
|
||||
<# } #>
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
<# if (IsNullable(t)) { #>
|
||||
return default;
|
||||
<# } else { #>
|
||||
throw Error.NoElements();
|
||||
<# } #>
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if( x == null) continue;
|
||||
<# } #>
|
||||
if (value <#= op #> x)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> value = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
value = await selector(e.Current, cancellationToken);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if(value == null) continue;
|
||||
<# } #>
|
||||
goto NEXT_LOOP;
|
||||
}
|
||||
|
||||
<# if (IsNullable(t)) { #>
|
||||
return default;
|
||||
<# } else { #>
|
||||
throw Error.NoElements();
|
||||
<# } #>
|
||||
NEXT_LOOP:
|
||||
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var x = await selector(e.Current, cancellationToken);
|
||||
<# if (IsNullable(t)) { #>
|
||||
if( x == null) continue;
|
||||
<# } #>
|
||||
if (value <#= op #> x)
|
||||
{
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> Never<T>()
|
||||
{
|
||||
return Cysharp.Threading.Tasks.Linq.Never<T>.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Never<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
public static readonly IUniTaskAsyncEnumerable<T> Instance = new Never<T>();
|
||||
|
||||
Never()
|
||||
{
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
public Enumerator(CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public T Current => default;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<bool>();
|
||||
|
||||
cancellationToken.Register(state =>
|
||||
{
|
||||
var task = (UniTaskCompletionSource<bool>)state;
|
||||
task.TrySetCanceled(cancellationToken);
|
||||
}, tcs);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TResult> OfType<TResult>(this IUniTaskAsyncEnumerable<Object> source)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new OfType<TResult>(source);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class OfType<TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<object> source;
|
||||
|
||||
public OfType(IUniTaskAsyncEnumerable<object> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<object, TResult>
|
||||
{
|
||||
public Enumerator(IUniTaskAsyncEnumerable<object> source, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (SourceCurrent is TResult castCurent)
|
||||
{
|
||||
Current = castCurent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,556 +0,0 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
#region OrderBy_OrderByDescending
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderBy<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderBy<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerableAwait<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerableAwait<TSource, TKey>(source, keySelector, comparer, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerableAwaitWithCancellation<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerableAwaitWithCancellation<TSource, TKey>(source, keySelector, comparer, false, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescending<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, true, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescending<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer, true, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescendingAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerableAwait<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, true, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescendingAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerableAwait<TSource, TKey>(source, keySelector, comparer, true, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return new OrderedAsyncEnumerableAwaitWithCancellation<TSource, TKey>(source, keySelector, Comparer<TKey>.Default, true, null);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> OrderByDescendingAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return new OrderedAsyncEnumerableAwaitWithCancellation<TSource, TKey>(source, keySelector, comparer, true, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ThenBy_ThenByDescending
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenBy<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenBy<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByAwait<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByAwait<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByAwaitWithCancellation<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByAwaitWithCancellation<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, false);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescending<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, true);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescending<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, true);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescendingAwait<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, true);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescendingAwait<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, true);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitWithCancellation<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, Comparer<TKey>.Default, true);
|
||||
}
|
||||
|
||||
public static IUniTaskOrderedAsyncEnumerable<TSource> ThenByDescendingAwaitWithCancellation<TSource, TKey>(this IUniTaskOrderedAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return source.CreateOrderedEnumerable(keySelector, comparer, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal abstract class AsyncEnumerableSorter<TElement>
|
||||
{
|
||||
internal abstract UniTask ComputeKeysAsync(TElement[] elements, int count);
|
||||
|
||||
internal abstract int CompareKeys(int index1, int index2);
|
||||
|
||||
internal async UniTask<int[]> SortAsync(TElement[] elements, int count)
|
||||
{
|
||||
await ComputeKeysAsync(elements, count);
|
||||
|
||||
int[] map = new int[count];
|
||||
for (int i = 0; i < count; i++) map[i] = i;
|
||||
QuickSort(map, 0, count - 1);
|
||||
return map;
|
||||
}
|
||||
|
||||
void QuickSort(int[] map, int left, int right)
|
||||
{
|
||||
do
|
||||
{
|
||||
int i = left;
|
||||
int j = right;
|
||||
int x = map[i + ((j - i) >> 1)];
|
||||
do
|
||||
{
|
||||
while (i < map.Length && CompareKeys(x, map[i]) > 0) i++;
|
||||
while (j >= 0 && CompareKeys(x, map[j]) < 0) j--;
|
||||
if (i > j) break;
|
||||
if (i < j)
|
||||
{
|
||||
int temp = map[i];
|
||||
map[i] = map[j];
|
||||
map[j] = temp;
|
||||
}
|
||||
i++;
|
||||
j--;
|
||||
} while (i <= j);
|
||||
if (j - left <= right - i)
|
||||
{
|
||||
if (left < j) QuickSort(map, left, j);
|
||||
left = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < right) QuickSort(map, i, right);
|
||||
right = j;
|
||||
}
|
||||
} while (left < right);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyncSelectorAsyncEnumerableSorter<TElement, TKey> : AsyncEnumerableSorter<TElement>
|
||||
{
|
||||
readonly Func<TElement, TKey> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly AsyncEnumerableSorter<TElement> next;
|
||||
TKey[] keys;
|
||||
|
||||
internal SyncSelectorAsyncEnumerableSorter(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, AsyncEnumerableSorter<TElement> next)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
internal override async UniTask ComputeKeysAsync(TElement[] elements, int count)
|
||||
{
|
||||
keys = new TKey[count];
|
||||
for (int i = 0; i < count; i++) keys[i] = keySelector(elements[i]);
|
||||
if (next != null) await next.ComputeKeysAsync(elements, count);
|
||||
}
|
||||
|
||||
internal override int CompareKeys(int index1, int index2)
|
||||
{
|
||||
int c = comparer.Compare(keys[index1], keys[index2]);
|
||||
if (c == 0)
|
||||
{
|
||||
if (next == null) return index1 - index2;
|
||||
return next.CompareKeys(index1, index2);
|
||||
}
|
||||
return descending ? -c : c;
|
||||
}
|
||||
}
|
||||
|
||||
internal class AsyncSelectorEnumerableSorter<TElement, TKey> : AsyncEnumerableSorter<TElement>
|
||||
{
|
||||
readonly Func<TElement, UniTask<TKey>> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly AsyncEnumerableSorter<TElement> next;
|
||||
TKey[] keys;
|
||||
|
||||
internal AsyncSelectorEnumerableSorter(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending, AsyncEnumerableSorter<TElement> next)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
internal override async UniTask ComputeKeysAsync(TElement[] elements, int count)
|
||||
{
|
||||
keys = new TKey[count];
|
||||
for (int i = 0; i < count; i++) keys[i] = await keySelector(elements[i]);
|
||||
if (next != null) await next.ComputeKeysAsync(elements, count);
|
||||
}
|
||||
|
||||
internal override int CompareKeys(int index1, int index2)
|
||||
{
|
||||
int c = comparer.Compare(keys[index1], keys[index2]);
|
||||
if (c == 0)
|
||||
{
|
||||
if (next == null) return index1 - index2;
|
||||
return next.CompareKeys(index1, index2);
|
||||
}
|
||||
return descending ? -c : c;
|
||||
}
|
||||
}
|
||||
|
||||
internal class AsyncSelectorWithCancellationEnumerableSorter<TElement, TKey> : AsyncEnumerableSorter<TElement>
|
||||
{
|
||||
readonly Func<TElement, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly AsyncEnumerableSorter<TElement> next;
|
||||
CancellationToken cancellationToken;
|
||||
TKey[] keys;
|
||||
|
||||
internal AsyncSelectorWithCancellationEnumerableSorter(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending, AsyncEnumerableSorter<TElement> next, CancellationToken cancellationToken)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.next = next;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
internal override async UniTask ComputeKeysAsync(TElement[] elements, int count)
|
||||
{
|
||||
keys = new TKey[count];
|
||||
for (int i = 0; i < count; i++) keys[i] = await keySelector(elements[i], cancellationToken);
|
||||
if (next != null) await next.ComputeKeysAsync(elements, count);
|
||||
}
|
||||
|
||||
internal override int CompareKeys(int index1, int index2)
|
||||
{
|
||||
int c = comparer.Compare(keys[index1], keys[index2]);
|
||||
if (c == 0)
|
||||
{
|
||||
if (next == null) return index1 - index2;
|
||||
return next.CompareKeys(index1, index2);
|
||||
}
|
||||
return descending ? -c : c;
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class OrderedAsyncEnumerable<TElement> : IUniTaskOrderedAsyncEnumerable<TElement>
|
||||
{
|
||||
protected readonly IUniTaskAsyncEnumerable<TElement> source;
|
||||
|
||||
public OrderedAsyncEnumerable(IUniTaskAsyncEnumerable<TElement> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
|
||||
{
|
||||
return new OrderedAsyncEnumerable<TElement, TKey>(source, keySelector, comparer, descending, this);
|
||||
}
|
||||
|
||||
public IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending)
|
||||
{
|
||||
return new OrderedAsyncEnumerableAwait<TElement, TKey>(source, keySelector, comparer, descending, this);
|
||||
}
|
||||
|
||||
public IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending)
|
||||
{
|
||||
return new OrderedAsyncEnumerableAwaitWithCancellation<TElement, TKey>(source, keySelector, comparer, descending, this);
|
||||
}
|
||||
|
||||
internal abstract AsyncEnumerableSorter<TElement> GetAsyncEnumerableSorter(AsyncEnumerableSorter<TElement> next, CancellationToken cancellationToken);
|
||||
|
||||
public IUniTaskAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(this, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TElement>
|
||||
{
|
||||
protected readonly OrderedAsyncEnumerable<TElement> parent;
|
||||
CancellationToken cancellationToken;
|
||||
TElement[] buffer;
|
||||
int[] map;
|
||||
int index;
|
||||
|
||||
public Enumerator(OrderedAsyncEnumerable<TElement> parent, CancellationToken cancellationToken)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TElement Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
completionSource.Reset();
|
||||
CreateSortSource().Forget();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
if (index < buffer.Length)
|
||||
{
|
||||
Current = buffer[map[index++]];
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid CreateSortSource()
|
||||
{
|
||||
try
|
||||
{
|
||||
buffer = await parent.source.ToArrayAsync();
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sorter = parent.GetAsyncEnumerableSorter(null, cancellationToken);
|
||||
map = await sorter.SortAsync(buffer, buffer.Length);
|
||||
sorter = null;
|
||||
|
||||
// set first value
|
||||
Current = buffer[map[index++]];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrderedAsyncEnumerable<TElement, TKey> : OrderedAsyncEnumerable<TElement>
|
||||
{
|
||||
readonly Func<TElement, TKey> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly OrderedAsyncEnumerable<TElement> parent;
|
||||
|
||||
public OrderedAsyncEnumerable(IUniTaskAsyncEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, OrderedAsyncEnumerable<TElement> parent)
|
||||
: base(source)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
internal override AsyncEnumerableSorter<TElement> GetAsyncEnumerableSorter(AsyncEnumerableSorter<TElement> next, CancellationToken cancellationToken)
|
||||
{
|
||||
AsyncEnumerableSorter<TElement> sorter = new SyncSelectorAsyncEnumerableSorter<TElement, TKey>(keySelector, comparer, descending, next);
|
||||
if (parent != null) sorter = parent.GetAsyncEnumerableSorter(sorter, cancellationToken);
|
||||
return sorter;
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrderedAsyncEnumerableAwait<TElement, TKey> : OrderedAsyncEnumerable<TElement>
|
||||
{
|
||||
readonly Func<TElement, UniTask<TKey>> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly OrderedAsyncEnumerable<TElement> parent;
|
||||
|
||||
public OrderedAsyncEnumerableAwait(IUniTaskAsyncEnumerable<TElement> source, Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending, OrderedAsyncEnumerable<TElement> parent)
|
||||
: base(source)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
internal override AsyncEnumerableSorter<TElement> GetAsyncEnumerableSorter(AsyncEnumerableSorter<TElement> next, CancellationToken cancellationToken)
|
||||
{
|
||||
AsyncEnumerableSorter<TElement> sorter = new AsyncSelectorEnumerableSorter<TElement, TKey>(keySelector, comparer, descending, next);
|
||||
if (parent != null) sorter = parent.GetAsyncEnumerableSorter(sorter, cancellationToken);
|
||||
return sorter;
|
||||
}
|
||||
}
|
||||
|
||||
internal class OrderedAsyncEnumerableAwaitWithCancellation<TElement, TKey> : OrderedAsyncEnumerable<TElement>
|
||||
{
|
||||
readonly Func<TElement, CancellationToken, UniTask<TKey>> keySelector;
|
||||
readonly IComparer<TKey> comparer;
|
||||
readonly bool descending;
|
||||
readonly OrderedAsyncEnumerable<TElement> parent;
|
||||
|
||||
public OrderedAsyncEnumerableAwaitWithCancellation(IUniTaskAsyncEnumerable<TElement> source, Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending, OrderedAsyncEnumerable<TElement> parent)
|
||||
: base(source)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
this.descending = descending;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
internal override AsyncEnumerableSorter<TElement> GetAsyncEnumerableSorter(AsyncEnumerableSorter<TElement> next, CancellationToken cancellationToken)
|
||||
{
|
||||
AsyncEnumerableSorter<TElement> sorter = new AsyncSelectorWithCancellationEnumerableSorter<TElement, TKey>(keySelector, comparer, descending, next, cancellationToken);
|
||||
if (parent != null) sorter = parent.GetAsyncEnumerableSorter(sorter, cancellationToken);
|
||||
return sorter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<int> Range(int start, int count)
|
||||
{
|
||||
if (count < 0) throw Error.ArgumentOutOfRange(nameof(count));
|
||||
|
||||
var end = (long)start + count - 1L;
|
||||
if (end > int.MaxValue) throw Error.ArgumentOutOfRange(nameof(count));
|
||||
|
||||
if (count == 0) UniTaskAsyncEnumerable.Empty<int>();
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.Range(start, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Range : IUniTaskAsyncEnumerable<int>
|
||||
{
|
||||
readonly int start;
|
||||
readonly int end;
|
||||
|
||||
public Range(int start, int count)
|
||||
{
|
||||
this.start = start;
|
||||
this.end = start + count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(start, end, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<int>
|
||||
{
|
||||
readonly int start;
|
||||
readonly int end;
|
||||
int current;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
public Enumerator(int start, int end, CancellationToken cancellationToken)
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
this.current = start - 1;
|
||||
}
|
||||
|
||||
public int Current => current;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
current++;
|
||||
|
||||
if (current != end)
|
||||
{
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TElement> Repeat<TElement>(TElement element, int count)
|
||||
{
|
||||
if (count < 0) throw Error.ArgumentOutOfRange(nameof(count));
|
||||
|
||||
return new Repeat<TElement>(element, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Repeat<TElement> : IUniTaskAsyncEnumerable<TElement>
|
||||
{
|
||||
readonly TElement element;
|
||||
readonly int count;
|
||||
|
||||
public Repeat(TElement element, int count)
|
||||
{
|
||||
this.element = element;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(element, count, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<TElement>
|
||||
{
|
||||
readonly TElement element;
|
||||
readonly int count;
|
||||
int remaining;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
public Enumerator(TElement element, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
this.element = element;
|
||||
this.count = count;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
this.remaining = count;
|
||||
}
|
||||
|
||||
public TElement Current => element;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (remaining-- != 0)
|
||||
{
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TValue> Return<TValue>(TValue value)
|
||||
{
|
||||
return new Return<TValue>(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Return<TValue> : IUniTaskAsyncEnumerable<TValue>
|
||||
{
|
||||
readonly TValue value;
|
||||
|
||||
public Return(TValue value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TValue> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(value, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<TValue>
|
||||
{
|
||||
readonly TValue value;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
bool called;
|
||||
|
||||
public Enumerator(TValue value, CancellationToken cancellationToken)
|
||||
{
|
||||
this.value = value;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.called = false;
|
||||
}
|
||||
|
||||
public TValue Current => value;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!called)
|
||||
{
|
||||
called = true;
|
||||
return CompletedTasks.True;
|
||||
}
|
||||
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Reverse<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
return new Reverse<TSource>(source);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Reverse<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
|
||||
public Reverse(IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
TSource[] array;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
// after consumed array, don't use await so allow async(not require UniTaskCompletionSourceCore).
|
||||
public async UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (array == null)
|
||||
{
|
||||
array = await source.ToArrayAsync(cancellationToken);
|
||||
index = array.Length - 1;
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
Current = array[index];
|
||||
--index;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TResult> Select<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.Select<TSource, TResult>(source, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> Select<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, TResult> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.SelectInt<TSource, TResult>(source, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectAwait<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.SelectAwait<TSource, TResult>(source, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectAwait<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.SelectAwaitInt<TSource, TResult>(source, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectAwaitWithCancellation<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.SelectAwaitCancellation<TSource, TResult>(source, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectAwaitWithCancellation<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new Cysharp.Threading.Tasks.Linq.SelectAwaitIntCancellation<TSource, TResult>(source, selector);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Select<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, TResult> selector;
|
||||
|
||||
public Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorBase<TSource, TResult>
|
||||
{
|
||||
readonly Func<TSource, TResult> selector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
Current = selector(SourceCurrent);
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectInt<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, TResult> selector;
|
||||
|
||||
public SelectInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorBase<TSource, TResult>
|
||||
{
|
||||
readonly Func<TSource, int, TResult> selector;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
Current = selector(SourceCurrent, checked(index++));
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectAwait<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<TResult>> selector;
|
||||
|
||||
public SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult>
|
||||
{
|
||||
readonly Func<TSource, UniTask<TResult>> selector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return selector(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration)
|
||||
{
|
||||
Current = awaitResult;
|
||||
terminateIteration= false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectAwaitInt<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, UniTask<TResult>> selector;
|
||||
|
||||
public SelectAwaitInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult>
|
||||
{
|
||||
readonly Func<TSource, int, UniTask<TResult>> selector;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return selector(sourceCurrent, checked(index++));
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration)
|
||||
{
|
||||
Current = awaitResult;
|
||||
terminateIteration= false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectAwaitCancellation<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<TResult>> selector;
|
||||
|
||||
public SelectAwaitCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult>
|
||||
{
|
||||
readonly Func<TSource, CancellationToken, UniTask<TResult>> selector;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return selector(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration)
|
||||
{
|
||||
Current = awaitResult;
|
||||
terminateIteration= false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectAwaitIntCancellation<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector;
|
||||
|
||||
public SelectAwaitIntCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<TResult>> selector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TResult, TResult>
|
||||
{
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
protected override UniTask<TResult> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return selector(sourceCurrent, checked(index++), cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(TResult awaitResult, out bool terminateIteration)
|
||||
{
|
||||
Current = awaitResult;
|
||||
terminateIteration= false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,886 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectMany<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, IUniTaskAsyncEnumerable<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectMany<TSource, TResult, TResult>(source, selector, (x, y) => y);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectMany<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, IUniTaskAsyncEnumerable<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectMany<TSource, TResult, TResult>(source, selector, (x, y) => y);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, IUniTaskAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectMany<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, IUniTaskAsyncEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectMany<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwait<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<IUniTaskAsyncEnumerable<TResult>>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectManyAwait<TSource, TResult, TResult>(source, selector, (x, y) => UniTask.FromResult(y));
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwait<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<IUniTaskAsyncEnumerable<TResult>>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectManyAwait<TSource, TResult, TResult>(source, selector, (x, y) => UniTask.FromResult(y));
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwait<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<IUniTaskAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectManyAwait<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwait<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<IUniTaskAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectManyAwait<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwaitWithCancellation<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TResult>>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectManyAwaitWithCancellation<TSource, TResult, TResult>(source, selector, (x, y, c) => UniTask.FromResult(y));
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwaitWithCancellation<TSource, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TResult>>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new SelectManyAwaitWithCancellation<TSource, TResult, TResult>(source, selector, (x, y, c) => UniTask.FromResult(y));
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwaitWithCancellation<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectManyAwaitWithCancellation<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> SelectManyAwaitWithCancellation<TSource, TCollection, TResult>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> collectionSelector, Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(collectionSelector, nameof(collectionSelector));
|
||||
|
||||
return new SelectManyAwaitWithCancellation<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectMany<TSource, TCollection, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, IUniTaskAsyncEnumerable<TCollection>> selector1;
|
||||
readonly Func<TSource, int, IUniTaskAsyncEnumerable<TCollection>> selector2;
|
||||
readonly Func<TSource, TCollection, TResult> resultSelector;
|
||||
|
||||
public SelectMany(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, IUniTaskAsyncEnumerable<TCollection>> selector, Func<TSource, TCollection, TResult> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector;
|
||||
this.selector2 = null;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public SelectMany(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, IUniTaskAsyncEnumerable<TCollection>> selector, Func<TSource, TCollection, TResult> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = null;
|
||||
this.selector2 = selector;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector1, selector2, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> sourceMoveNextCoreDelegate = SourceMoveNextCore;
|
||||
static readonly Action<object> selectedSourceMoveNextCoreDelegate = SeletedSourceMoveNextCore;
|
||||
static readonly Action<object> selectedEnumeratorDisposeAsyncCoreDelegate = SelectedEnumeratorDisposeAsyncCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
|
||||
readonly Func<TSource, IUniTaskAsyncEnumerable<TCollection>> selector1;
|
||||
readonly Func<TSource, int, IUniTaskAsyncEnumerable<TCollection>> selector2;
|
||||
readonly Func<TSource, TCollection, TResult> resultSelector;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
TSource sourceCurrent;
|
||||
int sourceIndex;
|
||||
IUniTaskAsyncEnumerator<TSource> sourceEnumerator;
|
||||
IUniTaskAsyncEnumerator<TCollection> selectedEnumerator;
|
||||
UniTask<bool>.Awaiter sourceAwaiter;
|
||||
UniTask<bool>.Awaiter selectedAwaiter;
|
||||
UniTask.Awaiter selectedDisposeAsyncAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, IUniTaskAsyncEnumerable<TCollection>> selector1, Func<TSource, int, IUniTaskAsyncEnumerable<TCollection>> selector2, Func<TSource, TCollection, TResult> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector1;
|
||||
this.selector2 = selector2;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
completionSource.Reset();
|
||||
|
||||
// iterate selected field
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
MoveNextSelected();
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate source field
|
||||
if (sourceEnumerator == null)
|
||||
{
|
||||
sourceEnumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
MoveNextSource();
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void MoveNextSource()
|
||||
{
|
||||
try
|
||||
{
|
||||
sourceAwaiter = sourceEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceAwaiter.IsCompleted)
|
||||
{
|
||||
SourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceAwaiter.SourceOnCompleted(sourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveNextSelected()
|
||||
{
|
||||
try
|
||||
{
|
||||
selectedAwaiter = selectedEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedAwaiter.IsCompleted)
|
||||
{
|
||||
SeletedSourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedAwaiter.SourceOnCompleted(selectedSourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void SourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.sourceAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.sourceCurrent = self.sourceEnumerator.Current;
|
||||
if (self.selector1 != null)
|
||||
{
|
||||
self.selectedEnumerator = self.selector1(self.sourceCurrent).GetAsyncEnumerator(self.cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.selectedEnumerator = self.selector2(self.sourceCurrent, checked(self.sourceIndex++)).GetAsyncEnumerator(self.cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
self.MoveNextSelected(); // iterated selected source.
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SeletedSourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.Current = self.resultSelector(self.sourceCurrent, self.selectedEnumerator.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// dispose selected source and try iterate source.
|
||||
try
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter = self.selectedEnumerator.DisposeAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
if (self.selectedDisposeAsyncAwaiter.IsCompleted)
|
||||
{
|
||||
SelectedEnumeratorDisposeAsyncCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter.SourceOnCompleted(selectedEnumeratorDisposeAsyncCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectedEnumeratorDisposeAsyncCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
|
||||
{
|
||||
self.selectedEnumerator = null;
|
||||
self.selectedAwaiter = default;
|
||||
|
||||
self.MoveNextSource(); // iterate next source
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
await selectedEnumerator.DisposeAsync();
|
||||
}
|
||||
if (sourceEnumerator != null)
|
||||
{
|
||||
await sourceEnumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectManyAwait<TSource, TCollection, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1;
|
||||
readonly Func<TSource, int, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2;
|
||||
readonly Func<TSource, TCollection, UniTask<TResult>> resultSelector;
|
||||
|
||||
public SelectManyAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector, Func<TSource, TCollection, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector;
|
||||
this.selector2 = null;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public SelectManyAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector, Func<TSource, TCollection, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = null;
|
||||
this.selector2 = selector;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector1, selector2, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> sourceMoveNextCoreDelegate = SourceMoveNextCore;
|
||||
static readonly Action<object> selectedSourceMoveNextCoreDelegate = SeletedSourceMoveNextCore;
|
||||
static readonly Action<object> selectedEnumeratorDisposeAsyncCoreDelegate = SelectedEnumeratorDisposeAsyncCore;
|
||||
static readonly Action<object> selectorAwaitCoreDelegate = SelectorAwaitCore;
|
||||
static readonly Action<object> resultSelectorAwaitCoreDelegate = ResultSelectorAwaitCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
|
||||
readonly Func<TSource, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1;
|
||||
readonly Func<TSource, int, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2;
|
||||
readonly Func<TSource, TCollection, UniTask<TResult>> resultSelector;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
TSource sourceCurrent;
|
||||
int sourceIndex;
|
||||
IUniTaskAsyncEnumerator<TSource> sourceEnumerator;
|
||||
IUniTaskAsyncEnumerator<TCollection> selectedEnumerator;
|
||||
UniTask<bool>.Awaiter sourceAwaiter;
|
||||
UniTask<bool>.Awaiter selectedAwaiter;
|
||||
UniTask.Awaiter selectedDisposeAsyncAwaiter;
|
||||
|
||||
// await additional
|
||||
UniTask<IUniTaskAsyncEnumerable<TCollection>>.Awaiter collectionSelectorAwaiter;
|
||||
UniTask<TResult>.Awaiter resultSelectorAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1, Func<TSource, int, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2, Func<TSource, TCollection, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector1;
|
||||
this.selector2 = selector2;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
completionSource.Reset();
|
||||
|
||||
// iterate selected field
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
MoveNextSelected();
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate source field
|
||||
if (sourceEnumerator == null)
|
||||
{
|
||||
sourceEnumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
MoveNextSource();
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void MoveNextSource()
|
||||
{
|
||||
try
|
||||
{
|
||||
sourceAwaiter = sourceEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceAwaiter.IsCompleted)
|
||||
{
|
||||
SourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceAwaiter.SourceOnCompleted(sourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveNextSelected()
|
||||
{
|
||||
try
|
||||
{
|
||||
selectedAwaiter = selectedEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedAwaiter.IsCompleted)
|
||||
{
|
||||
SeletedSourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedAwaiter.SourceOnCompleted(selectedSourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void SourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.sourceAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.sourceCurrent = self.sourceEnumerator.Current;
|
||||
|
||||
if (self.selector1 != null)
|
||||
{
|
||||
self.collectionSelectorAwaiter = self.selector1(self.sourceCurrent).GetAwaiter();
|
||||
}
|
||||
else
|
||||
{
|
||||
self.collectionSelectorAwaiter = self.selector2(self.sourceCurrent, checked(self.sourceIndex++)).GetAwaiter();
|
||||
}
|
||||
|
||||
if (self.collectionSelectorAwaiter.IsCompleted)
|
||||
{
|
||||
SelectorAwaitCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.collectionSelectorAwaiter.SourceOnCompleted(selectorAwaitCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SeletedSourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.resultSelectorAwaiter = self.resultSelector(self.sourceCurrent, self.selectedEnumerator.Current).GetAwaiter();
|
||||
if (self.resultSelectorAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectorAwaitCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.resultSelectorAwaiter.SourceOnCompleted(resultSelectorAwaitCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// dispose selected source and try iterate source.
|
||||
try
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter = self.selectedEnumerator.DisposeAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
if (self.selectedDisposeAsyncAwaiter.IsCompleted)
|
||||
{
|
||||
SelectedEnumeratorDisposeAsyncCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter.SourceOnCompleted(selectedEnumeratorDisposeAsyncCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectedEnumeratorDisposeAsyncCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
|
||||
{
|
||||
self.selectedEnumerator = null;
|
||||
self.selectedAwaiter = default;
|
||||
|
||||
self.MoveNextSource(); // iterate next source
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectorAwaitCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.collectionSelectorAwaiter, out var result))
|
||||
{
|
||||
self.selectedEnumerator = result.GetAsyncEnumerator(self.cancellationToken);
|
||||
self.MoveNextSelected(); // iterated selected source.
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectorAwaitCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultSelectorAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
await selectedEnumerator.DisposeAsync();
|
||||
}
|
||||
if (sourceEnumerator != null)
|
||||
{
|
||||
await sourceEnumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SelectManyAwaitWithCancellation<TSource, TCollection, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2;
|
||||
readonly Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
|
||||
public SelectManyAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector, Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector;
|
||||
this.selector2 = null;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public SelectManyAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector, Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = null;
|
||||
this.selector2 = selector;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, selector1, selector2, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> sourceMoveNextCoreDelegate = SourceMoveNextCore;
|
||||
static readonly Action<object> selectedSourceMoveNextCoreDelegate = SeletedSourceMoveNextCore;
|
||||
static readonly Action<object> selectedEnumeratorDisposeAsyncCoreDelegate = SelectedEnumeratorDisposeAsyncCore;
|
||||
static readonly Action<object> selectorAwaitCoreDelegate = SelectorAwaitCore;
|
||||
static readonly Action<object> resultSelectorAwaitCoreDelegate = ResultSelectorAwaitCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
|
||||
readonly Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2;
|
||||
readonly Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
TSource sourceCurrent;
|
||||
int sourceIndex;
|
||||
IUniTaskAsyncEnumerator<TSource> sourceEnumerator;
|
||||
IUniTaskAsyncEnumerator<TCollection> selectedEnumerator;
|
||||
UniTask<bool>.Awaiter sourceAwaiter;
|
||||
UniTask<bool>.Awaiter selectedAwaiter;
|
||||
UniTask.Awaiter selectedDisposeAsyncAwaiter;
|
||||
|
||||
// await additional
|
||||
UniTask<IUniTaskAsyncEnumerable<TCollection>>.Awaiter collectionSelectorAwaiter;
|
||||
UniTask<TResult>.Awaiter resultSelectorAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector1, Func<TSource, int, CancellationToken, UniTask<IUniTaskAsyncEnumerable<TCollection>>> selector2, Func<TSource, TCollection, CancellationToken, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.selector1 = selector1;
|
||||
this.selector2 = selector2;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
completionSource.Reset();
|
||||
|
||||
// iterate selected field
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
MoveNextSelected();
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterate source field
|
||||
if (sourceEnumerator == null)
|
||||
{
|
||||
sourceEnumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
MoveNextSource();
|
||||
}
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void MoveNextSource()
|
||||
{
|
||||
try
|
||||
{
|
||||
sourceAwaiter = sourceEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceAwaiter.IsCompleted)
|
||||
{
|
||||
SourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceAwaiter.SourceOnCompleted(sourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveNextSelected()
|
||||
{
|
||||
try
|
||||
{
|
||||
selectedAwaiter = selectedEnumerator.MoveNextAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedAwaiter.IsCompleted)
|
||||
{
|
||||
SeletedSourceMoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedAwaiter.SourceOnCompleted(selectedSourceMoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void SourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.sourceAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.sourceCurrent = self.sourceEnumerator.Current;
|
||||
|
||||
if (self.selector1 != null)
|
||||
{
|
||||
self.collectionSelectorAwaiter = self.selector1(self.sourceCurrent, self.cancellationToken).GetAwaiter();
|
||||
}
|
||||
else
|
||||
{
|
||||
self.collectionSelectorAwaiter = self.selector2(self.sourceCurrent, checked(self.sourceIndex++), self.cancellationToken).GetAwaiter();
|
||||
}
|
||||
|
||||
if (self.collectionSelectorAwaiter.IsCompleted)
|
||||
{
|
||||
SelectorAwaitCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.collectionSelectorAwaiter.SourceOnCompleted(selectorAwaitCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SeletedSourceMoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedAwaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
self.resultSelectorAwaiter = self.resultSelector(self.sourceCurrent, self.selectedEnumerator.Current, self.cancellationToken).GetAwaiter();
|
||||
if (self.resultSelectorAwaiter.IsCompleted)
|
||||
{
|
||||
ResultSelectorAwaitCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.resultSelectorAwaiter.SourceOnCompleted(resultSelectorAwaitCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// dispose selected source and try iterate source.
|
||||
try
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter = self.selectedEnumerator.DisposeAsync().GetAwaiter();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
self.completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
if (self.selectedDisposeAsyncAwaiter.IsCompleted)
|
||||
{
|
||||
SelectedEnumeratorDisposeAsyncCore(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.selectedDisposeAsyncAwaiter.SourceOnCompleted(selectedEnumeratorDisposeAsyncCoreDelegate, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectedEnumeratorDisposeAsyncCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
|
||||
{
|
||||
self.selectedEnumerator = null;
|
||||
self.selectedAwaiter = default;
|
||||
|
||||
self.MoveNextSource(); // iterate next source
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectorAwaitCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.collectionSelectorAwaiter, out var result))
|
||||
{
|
||||
self.selectedEnumerator = result.GetAsyncEnumerator(self.cancellationToken);
|
||||
self.MoveNextSelected(); // iterated selected source.
|
||||
}
|
||||
}
|
||||
|
||||
static void ResultSelectorAwaitCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.resultSelectorAwaiter, out var result))
|
||||
{
|
||||
self.Current = result;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (selectedEnumerator != null)
|
||||
{
|
||||
await selectedEnumerator.DisposeAsync();
|
||||
}
|
||||
if (sourceEnumerator != null)
|
||||
{
|
||||
await sourceEnumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Boolean> SequenceEqualAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return SequenceEqualAsync(first, second, EqualityComparer<TSource>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Boolean> SequenceEqualAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return SequenceEqual.InvokeAsync(first, second, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SequenceEqual
|
||||
{
|
||||
internal static async UniTask<bool> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var e1 = first.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
var e2 = second.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (await e1.MoveNextAsync())
|
||||
{
|
||||
if (await e2.MoveNextAsync())
|
||||
{
|
||||
if (comparer.Equals(e1.Current, e2.Current))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// e2 is finished, but e1 has value
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// e1 is finished, e2?
|
||||
if (await e2.MoveNextAsync())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e2 != null)
|
||||
{
|
||||
await e2.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e1 != null)
|
||||
{
|
||||
await e1.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource> SingleAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleOrDefaultAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
|
||||
public static UniTask<TSource> SingleOrDefaultAwaitWithCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return SingleOperator.InvokeAsync(source, predicate, cancellationToken, true);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SingleOperator
|
||||
{
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
if (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (!await e.MoveNextAsync())
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
throw Error.MoreThanOneElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defaultIfEmpty)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Error.NoElements();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (predicate(v))
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
throw Error.MoreThanOneElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found || defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw Error.NoElements();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v))
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
throw Error.MoreThanOneElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found || defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw Error.NoElements();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<TSource> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate, CancellationToken cancellationToken, bool defaultIfEmpty)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
TSource value = default;
|
||||
bool found = false;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
if (await predicate(v, cancellationToken))
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
throw Error.MoreThanOneElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found || defaultIfEmpty)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw Error.NoElements();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Skip<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new Skip<TSource>(source, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Skip<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
|
||||
public Skip(IUniTaskAsyncEnumerable<TSource> source, int count)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly int count;
|
||||
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (count <= checked(index++))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipLast<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
// non skip.
|
||||
if (count <= 0)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
return new SkipLast<TSource>(source, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipLast<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
|
||||
public SkipLast(IUniTaskAsyncEnumerable<TSource> source, int count)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
Queue<TSource> queue;
|
||||
|
||||
bool continueNext;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
queue = new Queue<TSource>();
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (self.queue.Count == self.count)
|
||||
{
|
||||
self.continueNext = false;
|
||||
|
||||
var deq = self.queue.Dequeue();
|
||||
self.Current = deq;
|
||||
self.queue.Enqueue(self.enumerator.Current);
|
||||
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.queue.Enqueue(self.enumerator.Current);
|
||||
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhile<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhile<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhile<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhileInt<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhileAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhileAwait<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhileAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhileIntAwait<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhileAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhileAwaitWithCancellation<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipWhileAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new SkipWhileIntAwaitWithCancellation<TSource>(source, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhile<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, bool> predicate;
|
||||
|
||||
public SkipWhile(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
Func<TSource, bool> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate == null || !predicate(SourceCurrent))
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhileInt<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, bool> predicate;
|
||||
|
||||
public SkipWhileInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
Func<TSource, int, bool> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate == null || !predicate(SourceCurrent, checked(index++)))
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhileAwait<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public SkipWhileAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
if (predicate == null)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
return predicate(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (!awaitResult)
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
terminateIteration= false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration= false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhileIntAwait<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, UniTask<bool>> predicate;
|
||||
|
||||
public SkipWhileIntAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, int, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
if (predicate == null)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
return predicate(sourceCurrent, checked(index++));
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration= false;
|
||||
if (!awaitResult)
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhileAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public SkipWhileAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
if (predicate == null)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
return predicate(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration= false;
|
||||
if (!awaitResult)
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipWhileIntAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public SkipWhileIntAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
if (predicate == null)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
return predicate(sourceCurrent, checked(index++), cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration= false;
|
||||
if (!awaitResult)
|
||||
{
|
||||
predicate = null;
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,167 +0,0 @@
|
||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#
|
||||
var types = new[]
|
||||
{
|
||||
typeof(int),
|
||||
typeof(long),
|
||||
typeof(float),
|
||||
typeof(double),
|
||||
typeof(decimal),
|
||||
|
||||
typeof(int?),
|
||||
typeof(long?),
|
||||
typeof(float?),
|
||||
typeof(double?),
|
||||
typeof(decimal?),
|
||||
};
|
||||
|
||||
Func<Type, bool> IsNullable = x => x.IsGenericType;
|
||||
Func<Type, string> TypeName = x => IsNullable(x) ? x.GetGenericArguments()[0].Name + "?" : x.Name;
|
||||
Func<Type, string> WithSuffix = x => IsNullable(x) ? ".GetValueOrDefault()" : "";
|
||||
#>
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
<# foreach(var t in types) { #>
|
||||
public static UniTask<<#= TypeName(t) #>> SumAsync(this IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Sum.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> SumAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Sum.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> SumAwaitAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Sum.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<<#= TypeName(t) #>> SumAwaitCancellationAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(selector));
|
||||
|
||||
return Sum.InvokeAsync(source, selector, cancellationToken);
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
|
||||
internal static class Sum
|
||||
{
|
||||
<# foreach(var t in types) { #>
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync(IUniTaskAsyncEnumerable<<#= TypeName(t) #>> source, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> sum = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
sum += e.Current<#= WithSuffix(t) #>;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, <#= TypeName(t) #>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> sum = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
sum += selector(e.Current)<#= WithSuffix(t) #>;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> sum = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
sum += (await selector(e.Current))<#= WithSuffix(t) #>;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static async UniTask<<#= TypeName(t) #>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<<#= TypeName(t) #>>> selector, CancellationToken cancellationToken)
|
||||
{
|
||||
<#= TypeName(t) #> sum = default;
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
sum += (await selector(e.Current, cancellationToken))<#= WithSuffix(t) #>;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Take<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new Take<TSource>(source, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Take<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
|
||||
public Take(IUniTaskAsyncEnumerable<TSource> source, int count)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly int count;
|
||||
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (checked(index++) < count)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeLast<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Int32 count)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
// non take.
|
||||
if (count <= 0)
|
||||
{
|
||||
return Empty<TSource>();
|
||||
}
|
||||
|
||||
return new TakeLast<TSource>(source, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeLast<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
|
||||
public TakeLast(IUniTaskAsyncEnumerable<TSource> source, int count)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, count, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly int count;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
Queue<TSource> queue;
|
||||
|
||||
bool iterateCompleted;
|
||||
bool continueNext;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
this.source = source;
|
||||
this.count = count;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||
queue = new Queue<TSource>();
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
if (iterateCompleted)
|
||||
{
|
||||
if (queue.Count > 0)
|
||||
{
|
||||
Current = queue.Dequeue();
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP; // avoid recursive
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (Enumerator)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (self.queue.Count < self.count)
|
||||
{
|
||||
self.queue.Enqueue(self.enumerator.Current);
|
||||
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.queue.Dequeue();
|
||||
self.queue.Enqueue(self.enumerator.Current);
|
||||
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.iterateCompleted = true;
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.continueNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhile<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhile<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhile<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhileInt<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhileAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhileAwait<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhileAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhileIntAwait<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhileAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhileAwaitWithCancellation<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeWhileAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new TakeWhileIntAwaitWithCancellation<TSource>(source, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhile<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, bool> predicate;
|
||||
|
||||
public TakeWhile(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
Func<TSource, bool> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate(SourceCurrent))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhileInt<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, bool> predicate;
|
||||
|
||||
public TakeWhileInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly Func<TSource, int, bool> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate(SourceCurrent, checked(index++)))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhileAwait<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public TakeWhileAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhileIntAwait<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, UniTask<bool>> predicate;
|
||||
|
||||
public TakeWhileIntAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, int, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, checked(index++));
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhileAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public TakeWhileAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeWhileIntAwaitWithCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public TakeWhileIntAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, checked(index++), cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
terminateIteration = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateIteration = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TValue> Throw<TValue>(Exception exception)
|
||||
{
|
||||
return new Throw<TValue>(exception);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Throw<TValue> : IUniTaskAsyncEnumerable<TValue>
|
||||
{
|
||||
readonly Exception exception;
|
||||
|
||||
public Throw(Exception exception)
|
||||
{
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TValue> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(exception, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : IUniTaskAsyncEnumerator<TValue>
|
||||
{
|
||||
readonly Exception exception;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
public Enumerator(Exception exception, CancellationToken cancellationToken)
|
||||
{
|
||||
this.exception = exception;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TValue Current => default;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return UniTask.FromException<bool>(exception);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<TSource[]> ToArrayAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ToArray.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ToArray
|
||||
{
|
||||
internal static async UniTask<TSource[]> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
TSource[] result = default;
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
result = Array.Empty<TSource>();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new TSource[i];
|
||||
Array.Copy(array, result, i);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAwaitAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAwaitAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAwaitAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAwaitAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAwaitWithCancellationAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TSource>> ToDictionaryAwaitWithCancellationAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAwaitWithCancellationAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<Dictionary<TKey, TElement>> ToDictionaryAwaitWithCancellationAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToDictionary.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ToDictionary
|
||||
{
|
||||
internal static async UniTask<Dictionary<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TSource>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = keySelector(v);
|
||||
dict.Add(key, v);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
internal static async UniTask<Dictionary<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TElement>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = keySelector(v);
|
||||
var value = elementSelector(v);
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
// with await
|
||||
|
||||
internal static async UniTask<Dictionary<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TSource>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = await keySelector(v);
|
||||
dict.Add(key, v);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
internal static async UniTask<Dictionary<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TElement>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = await keySelector(v);
|
||||
var value = await elementSelector(v);
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
// with cancellation
|
||||
|
||||
internal static async UniTask<Dictionary<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TSource>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = await keySelector(v, cancellationToken);
|
||||
dict.Add(key, v);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
internal static async UniTask<Dictionary<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, TElement>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
var v = e.Current;
|
||||
var key = await keySelector(v, cancellationToken);
|
||||
var value = await elementSelector(v, cancellationToken);
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<HashSet<TSource>> ToHashSetAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ToHashSet.InvokeAsync(source, EqualityComparer<TSource>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<HashSet<TSource>> ToHashSetAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ToHashSet.InvokeAsync(source, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ToHashSet
|
||||
{
|
||||
internal static async UniTask<HashSet<TSource>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var set = new HashSet<TSource>(comparer);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
set.Add(e.Current);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<List<TSource>> ToListAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return Cysharp.Threading.Tasks.Linq.ToList.InvokeAsync(source, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ToList
|
||||
{
|
||||
internal static async UniTask<List<TSource>> InvokeAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<TSource>();
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
list.Add(e.Current);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,554 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAwaitAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAwaitAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAwaitAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAwaitAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAwaitWithCancellationAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TSource>> ToLookupAwaitWithCancellationAsync<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, comparer, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAwaitWithCancellationAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<ILookup<TKey, TElement>> ToLookupAwaitWithCancellationAsync<TSource, TKey, TElement>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
|
||||
Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
return ToLookup.InvokeAsync(source, keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ToLookup
|
||||
{
|
||||
internal static async UniTask<ILookup<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TSource>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Lookup<TKey, TSource>.Create(new ArraySegment<TSource>(array, 0, i), keySelector, comparer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<ILookup<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TElement>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Lookup<TKey, TElement>.Create(new ArraySegment<TSource>(array, 0, i), keySelector, elementSelector, comparer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// with await
|
||||
|
||||
internal static async UniTask<ILookup<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TSource>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return await Lookup<TKey, TSource>.CreateAsync(new ArraySegment<TSource>(array, 0, i), keySelector, comparer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<ILookup<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TElement>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return await Lookup<TKey, TElement>.CreateAsync(new ArraySegment<TSource>(array, 0, i), keySelector, elementSelector, comparer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// with cancellation
|
||||
|
||||
internal static async UniTask<ILookup<TKey, TSource>> InvokeAsync<TSource, TKey>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TSource>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return await Lookup<TKey, TSource>.CreateAsync(new ArraySegment<TSource>(array, 0, i), keySelector, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static async UniTask<ILookup<TKey, TElement>> InvokeAsync<TSource, TKey, TElement>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
IUniTaskAsyncEnumerator<TSource> e = default;
|
||||
try
|
||||
{
|
||||
e = source.GetAsyncEnumerator(cancellationToken);
|
||||
var i = 0;
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
ArrayPoolUtil.EnsureCapacity(ref array, i, pool);
|
||||
array[i++] = e.Current;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
return Lookup<TKey, TElement>.CreateEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
return await Lookup<TKey, TElement>.CreateAsync(new ArraySegment<TSource>(array, 0, i), keySelector, elementSelector, comparer, cancellationToken);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType<TSource>());
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup
|
||||
|
||||
class Lookup<TKey, TElement> : ILookup<TKey, TElement>
|
||||
{
|
||||
static readonly Lookup<TKey, TElement> empty = new Lookup<TKey, TElement>(new Dictionary<TKey, Grouping<TKey, TElement>>());
|
||||
|
||||
// original lookup keeps order but this impl does not(dictionary not guarantee)
|
||||
readonly Dictionary<TKey, Grouping<TKey, TElement>> dict;
|
||||
|
||||
Lookup(Dictionary<TKey, Grouping<TKey, TElement>> dict)
|
||||
{
|
||||
this.dict = dict;
|
||||
}
|
||||
|
||||
public static Lookup<TKey, TElement> CreateEmpty()
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
public static Lookup<TKey, TElement> Create(ArraySegment<TElement> source, Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = keySelector(arr[i]);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(arr[i]);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public static Lookup<TKey, TElement> Create<TSource>(ArraySegment<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = keySelector(arr[i]);
|
||||
var elem = elementSelector(arr[i]);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(elem);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public static async UniTask<Lookup<TKey, TElement>> CreateAsync(ArraySegment<TElement> source, Func<TElement, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = await keySelector(arr[i]);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(arr[i]);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public static async UniTask<Lookup<TKey, TElement>> CreateAsync<TSource>(ArraySegment<TSource> source, Func<TSource, UniTask<TKey>> keySelector, Func<TSource, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = await keySelector(arr[i]);
|
||||
var elem = await elementSelector(arr[i]);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(elem);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public static async UniTask<Lookup<TKey, TElement>> CreateAsync(ArraySegment<TElement> source, Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = await keySelector(arr[i], cancellationToken);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(arr[i]);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public static async UniTask<Lookup<TKey, TElement>> CreateAsync<TSource>(ArraySegment<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, Func<TSource, CancellationToken, UniTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
|
||||
{
|
||||
var dict = new Dictionary<TKey, Grouping<TKey, TElement>>(comparer);
|
||||
|
||||
var arr = source.Array;
|
||||
var c = source.Count;
|
||||
for (int i = source.Offset; i < c; i++)
|
||||
{
|
||||
var key = await keySelector(arr[i], cancellationToken);
|
||||
var elem = await elementSelector(arr[i], cancellationToken);
|
||||
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
list = new Grouping<TKey, TElement>(key);
|
||||
dict[key] = list;
|
||||
}
|
||||
|
||||
list.Add(elem);
|
||||
}
|
||||
|
||||
return new Lookup<TKey, TElement>(dict);
|
||||
}
|
||||
|
||||
public IEnumerable<TElement> this[TKey key] => dict.TryGetValue(key, out var g) ? g : Enumerable.Empty<TElement>();
|
||||
|
||||
public int Count => dict.Count;
|
||||
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
return dict.ContainsKey(key);
|
||||
}
|
||||
|
||||
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
|
||||
{
|
||||
return dict.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return dict.Values.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
class Grouping<TKey, TElement> : IGrouping<TKey, TElement> // , IUniTaskAsyncGrouping<TKey, TElement>
|
||||
{
|
||||
readonly List<TElement> elements;
|
||||
|
||||
public TKey Key { get; private set; }
|
||||
|
||||
public Grouping(TKey key)
|
||||
{
|
||||
this.Key = key;
|
||||
this.elements = new List<TElement>();
|
||||
}
|
||||
|
||||
public void Add(TElement value)
|
||||
{
|
||||
elements.Add(value);
|
||||
}
|
||||
public IEnumerator<TElement> GetEnumerator()
|
||||
{
|
||||
return elements.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return elements.GetEnumerator();
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return this.ToUniTaskAsyncEnumerable().GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Key: " + Key + ", Count: " + elements.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IObservable<TSource> ToObservable<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new ToObservable<TSource>(source);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ToObservable<T> : IObservable<T>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<T> source;
|
||||
|
||||
public ToObservable(IUniTaskAsyncEnumerable<T> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<T> observer)
|
||||
{
|
||||
var ctd = new CancellationTokenDisposable();
|
||||
|
||||
RunAsync(source, observer, ctd.Token).Forget();
|
||||
|
||||
return ctd;
|
||||
}
|
||||
|
||||
static async UniTaskVoid RunAsync(IUniTaskAsyncEnumerable<T> src, IObserver<T> observer, CancellationToken cancellationToken)
|
||||
{
|
||||
// cancellationToken.IsCancellationRequested is called when Rx's Disposed.
|
||||
// when disposed, finish silently.
|
||||
|
||||
var e = src.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
bool hasNext;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
hasNext = await e.MoveNextAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
observer.OnError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasNext)
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
observer.OnCompleted();
|
||||
return;
|
||||
}
|
||||
} while (!cancellationToken.IsCancellationRequested);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CancellationTokenDisposable : IDisposable
|
||||
{
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
public CancellationToken Token => cts.Token;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Union<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return Union<TSource>(first, second, EqualityComparer<TSource>.Default);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Union<TSource>(this IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(comparer, nameof(comparer));
|
||||
|
||||
// improv without combinate?
|
||||
return first.Concat(second).Distinct(comparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,355 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> Where<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new Where<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> Where<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, Boolean> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new WhereInt<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> WhereAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new WhereAwait<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> WhereAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new WhereAwaitInt<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> WhereAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new WhereAwaitCancellation<TSource>(source, predicate);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> WhereAwaitWithCancellation<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, Int32, CancellationToken, UniTask<Boolean>> predicate)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(predicate, nameof(predicate));
|
||||
|
||||
return new WhereAwaitIntCancellation<TSource>(source, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Where<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, bool> predicate;
|
||||
|
||||
public Where(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly Func<TSource, bool> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate(SourceCurrent))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WhereInt<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, bool> predicate;
|
||||
|
||||
public WhereInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorBase<TSource, TSource>
|
||||
{
|
||||
readonly Func<TSource, int, bool> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
|
||||
{
|
||||
if (sourceHasCurrent)
|
||||
{
|
||||
if (predicate(SourceCurrent, checked(index++)))
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
result = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WhereAwait<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public WhereAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration = false;
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WhereAwaitInt<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, UniTask<bool>> predicate;
|
||||
|
||||
public WhereAwaitInt(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, int, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, checked(index++));
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration = false;
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal sealed class WhereAwaitCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public WhereAwaitCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration = false;
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class WhereAwaitIntCancellation<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
|
||||
public WhereAwaitIntCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate)
|
||||
{
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(source, predicate, cancellationToken);
|
||||
}
|
||||
|
||||
class Enumerator : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, bool>
|
||||
{
|
||||
readonly Func<TSource, int, CancellationToken, UniTask<bool>> predicate;
|
||||
int index;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<bool>> predicate, CancellationToken cancellationToken)
|
||||
|
||||
: base(source, cancellationToken)
|
||||
{
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
protected override UniTask<bool> TransformAsync(TSource sourceCurrent)
|
||||
{
|
||||
return predicate(sourceCurrent, checked(index++), cancellationToken);
|
||||
}
|
||||
|
||||
protected override bool TrySetCurrentCore(bool awaitResult, out bool terminateIteration)
|
||||
{
|
||||
terminateIteration = false;
|
||||
if (awaitResult)
|
||||
{
|
||||
Current = SourceCurrent;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,535 +0,0 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
|
||||
return Zip(first, second, (x, y) => (x, y));
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector));
|
||||
|
||||
return new Zip<TFirst, TSecond, TResult>(first, second, resultSelector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> ZipAwait<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new ZipAwait<TFirst, TSecond, TResult>(first, second, selector);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TResult> ZipAwaitWithCancellation<TFirst, TSecond, TResult>(this IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> selector)
|
||||
{
|
||||
Error.ThrowArgumentNullException(first, nameof(first));
|
||||
Error.ThrowArgumentNullException(second, nameof(second));
|
||||
Error.ThrowArgumentNullException(selector, nameof(selector));
|
||||
|
||||
return new ZipAwaitWithCancellation<TFirst, TSecond, TResult>(first, second, selector);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Zip<TFirst, TSecond, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, TResult> resultSelector;
|
||||
|
||||
public Zip(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore;
|
||||
static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, TResult> resultSelector;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TFirst> firstEnumerator;
|
||||
IUniTaskAsyncEnumerator<TSecond> secondEnumerator;
|
||||
|
||||
UniTask<bool>.Awaiter firstAwaiter;
|
||||
UniTask<bool>.Awaiter secondAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> 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<bool>(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.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);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask DisposeAsync()
|
||||
{
|
||||
if (firstEnumerator != null)
|
||||
{
|
||||
await firstEnumerator.DisposeAsync();
|
||||
}
|
||||
if (secondEnumerator != null)
|
||||
{
|
||||
await secondEnumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ZipAwait<TFirst, TSecond, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, UniTask<TResult>> resultSelector;
|
||||
|
||||
public ZipAwait(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore;
|
||||
static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore;
|
||||
static readonly Action<object> resultAwaitCoreDelegate = ResultAwaitCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, UniTask<TResult>> resultSelector;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TFirst> firstEnumerator;
|
||||
IUniTaskAsyncEnumerator<TSecond> secondEnumerator;
|
||||
|
||||
UniTask<bool>.Awaiter firstAwaiter;
|
||||
UniTask<bool>.Awaiter secondAwaiter;
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> 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<bool>(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).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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ZipAwaitWithCancellation<TFirst, TSecond, TResult> : IUniTaskAsyncEnumerable<TResult>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
|
||||
public ZipAwaitWithCancellation(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new Enumerator(first, second, resultSelector, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
|
||||
{
|
||||
static readonly Action<object> firstMoveNextCoreDelegate = FirstMoveNextCore;
|
||||
static readonly Action<object> secondMoveNextCoreDelegate = SecondMoveNextCore;
|
||||
static readonly Action<object> resultAwaitCoreDelegate = ResultAwaitCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TFirst> first;
|
||||
readonly IUniTaskAsyncEnumerable<TSecond> second;
|
||||
readonly Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
IUniTaskAsyncEnumerator<TFirst> firstEnumerator;
|
||||
IUniTaskAsyncEnumerator<TSecond> secondEnumerator;
|
||||
|
||||
UniTask<bool>.Awaiter firstAwaiter;
|
||||
UniTask<bool>.Awaiter secondAwaiter;
|
||||
UniTask<TResult>.Awaiter resultAwaiter;
|
||||
|
||||
public Enumerator(IUniTaskAsyncEnumerable<TFirst> first, IUniTaskAsyncEnumerable<TSecond> second, Func<TFirst, TSecond, CancellationToken, UniTask<TResult>> resultSelector, CancellationToken cancellationToken)
|
||||
{
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.resultSelector = resultSelector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
|
||||
public UniTask<bool> 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<bool>(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,54 +14,4 @@
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Linq\MinMax.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>MinMax.tt</DependentUpon>
|
||||
</None>
|
||||
<None Include="Linq\Sum.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Sum.tt</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Linq\Average.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>Average.cs</LastGenOutput>
|
||||
</None>
|
||||
<None Update="Linq\MinMax.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>MinMax.cs</LastGenOutput>
|
||||
</None>
|
||||
<None Update="Linq\Sum.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>Sum.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Linq\Average.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Average.tt</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Linq\MinMax.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>MinMax.tt</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Linq\Sum.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Sum.tt</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user