This commit is contained in:
PC-20230316NUNE\Administrator
2024-02-01 19:06:51 +08:00
parent aa4d6c3ce2
commit 877dca3b43
7518 changed files with 653768 additions and 162059 deletions

View File

@@ -0,0 +1,318 @@
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.AggregateAsync(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.AggregateAsync(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.AggregateAsync(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.AggregateAwaitAsync(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.AggregateAwaitAsync(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.AggregateAwaitAsync(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.AggregateAwaitWithCancellationAsync(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.AggregateAwaitWithCancellationAsync(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.AggregateAwaitWithCancellationAsync(source, seed, accumulator, resultSelector, cancellationToken);
}
}
internal static class Aggregate
{
internal static async UniTask<TSource> AggregateAsync<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> AggregateAsync<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> AggregateAsync<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> AggregateAwaitAsync<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> AggregateAwaitAsync<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> AggregateAwaitAsync<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> AggregateAwaitWithCancellationAsync<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> AggregateAwaitWithCancellationAsync<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> AggregateAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5dc68c05a4228c643937f6ebd185bcca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,108 @@
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.AllAsync(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.AllAwaitAsync(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.AllAwaitWithCancellationAsync(source, predicate, cancellationToken);
}
}
internal static class All
{
internal static async UniTask<bool> AllAsync<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> AllAwaitAsync<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> AllAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7271437e0033af2448b600ee248924dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,136 @@
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.AnyAsync(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.AnyAsync(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.AnyAwaitAsync(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.AnyAwaitWithCancellationAsync(source, predicate, cancellationToken);
}
}
internal static class Any
{
internal static async UniTask<bool> AnyAsync<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> AnyAsync<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> AnyAwaitAsync<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> AnyAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2b2e65745263994fbe34f3e0ec8eb12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,151 @@
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, false);
}
}
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 _AppendPrepend(source, element, append, cancellationToken);
}
sealed class _AppendPrepend : 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 _AppendPrepend(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;
TaskTracker.TrackActiveTask(this, 3);
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
completionSource.Reset();
if (enumerator == null)
{
if (state == State.RequirePrepend)
{
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 = (_AppendPrepend)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3268ec424b8055f45aa2a26d17c80468
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TSource> AsUniTaskAsyncEnumerable<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
{
return source;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69866e262589ea643bbc62a1d696077a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,356 @@
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
// note: refactor all inherit class and should remove this.
// see Select and Where.
internal 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;
TaskTracker.TrackActiveTask(this, 4);
}
// 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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
internal 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;
TaskTracker.TrackActiveTask(this, 4);
}
// 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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01ba1d3b17e13fb4c95740131c7e6e19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 58499f95012fb3c47bb7bcbc5862e562
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,345 @@
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 _Buffer(source, count, cancellationToken);
}
sealed class _Buffer : 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 _Buffer(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
{
this.source = source;
this.count = count;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_Buffer)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()
{
TaskTracker.RemoveTracking(this);
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 _BufferSkip(source, count, skip, cancellationToken);
}
sealed class _BufferSkip : 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 _BufferSkip(IUniTaskAsyncEnumerable<TSource> source, int count, int skip, CancellationToken cancellationToken)
{
this.source = source;
this.count = count;
this.skip = skip;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_BufferSkip)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 951310243334a3148a7872977cb31c5c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
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 _Cast(source, cancellationToken);
}
class _Cast : AsyncEnumeratorBase<object, TResult>
{
public _Cast(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: edebeae8b61352b428abe9ce8f3fc71a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6cb07f6e88287e34d9b9301a572284a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,164 @@
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 _Concat(first, second, cancellationToken);
}
sealed class _Concat : 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 _Concat(IUniTaskAsyncEnumerable<TSource> first, IUniTaskAsyncEnumerable<TSource> second, CancellationToken cancellationToken)
{
this.first = first;
this.second = second;
this.cancellationToken = cancellationToken;
this.iteratingState = IteratingState.IteratingFirst;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_Concat)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cb9e19c449127a459851a135ce7d527
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
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.ContainsAsync(source, value, comparer, cancellationToken);
}
}
internal static class Contains
{
internal static async UniTask<bool> ContainsAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36ab06d30f3223048b4f676e05431a7f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,144 @@
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.CountAsync(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.CountAsync(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.CountAwaitAsync(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.CountAwaitWithCancellationAsync(source, predicate, cancellationToken);
}
}
internal static class Count
{
internal static async UniTask<int> CountAsync<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> CountAsync<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> CountAwaitAsync<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> CountAwaitWithCancellationAsync<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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e606d38eed688574bb2ba89d983cc9bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,184 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<T> Create<T>(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
{
Error.ThrowArgumentNullException(create, nameof(create));
return new Create<T>(create);
}
}
public interface IAsyncWriter<T>
{
UniTask YieldAsync(T value);
}
internal sealed class Create<T> : IUniTaskAsyncEnumerable<T>
{
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
public Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
{
this.create = create;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Create(create, cancellationToken);
}
sealed class _Create : MoveNextSource, IUniTaskAsyncEnumerator<T>
{
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
readonly CancellationToken cancellationToken;
int state = -1;
AsyncWriter writer;
public _Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create, CancellationToken cancellationToken)
{
this.create = create;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
public T Current { get; private set; }
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
writer.Dispose();
return default;
}
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
{
writer = new AsyncWriter(this);
RunWriterTask(create(writer, cancellationToken)).Forget();
if (Volatile.Read(ref state) == -2)
{
return; // complete synchronously
}
state = 0; // wait YieldAsync, it set TrySetResult(true)
return;
}
case 0:
writer.SignalWriter();
return;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
}
async UniTaskVoid RunWriterTask(UniTask task)
{
try
{
await task;
goto DONE;
}
catch (Exception ex)
{
Volatile.Write(ref state, -2);
completionSource.TrySetException(ex);
return;
}
DONE:
Volatile.Write(ref state, -2);
completionSource.TrySetResult(false);
}
public void SetResult(T value)
{
Current = value;
completionSource.TrySetResult(true);
}
}
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>, IDisposable
{
readonly _Create enumerator;
UniTaskCompletionSourceCore<AsyncUnit> core;
public AsyncWriter(_Create enumerator)
{
this.enumerator = enumerator;
}
public void Dispose()
{
var status = core.GetStatus(core.Version);
if (status == UniTaskStatus.Pending)
{
core.TrySetCanceled();
}
}
public void GetResult(short token)
{
core.GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public UniTask YieldAsync(T value)
{
core.Reset();
enumerator.SetResult(value);
return new UniTask(this, core.Version);
}
public void SignalWriter()
{
core.TrySetResult(AsyncUnit.Default);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0202f723469f93945afa063bfb440d15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,142 @@
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 _DefaultIfEmpty(source, defaultValue, cancellationToken);
}
sealed class _DefaultIfEmpty : 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 _DefaultIfEmpty(IUniTaskAsyncEnumerable<TSource> source, TSource defaultValue, CancellationToken cancellationToken)
{
this.source = source;
this.defaultValue = defaultValue;
this.cancellationToken = cancellationToken;
this.iteratingState = IteratingState.Empty;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_DefaultIfEmpty)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19e437c039ad7e1478dbce1779ef8660
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,277 @@
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 DistinctAwaitWithCancellation<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 _Distinct(source, comparer, cancellationToken);
}
class _Distinct : AsyncEnumeratorBase<TSource, TSource>
{
readonly HashSet<TSource> set;
public _Distinct(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 _Distinct(source, keySelector, comparer, cancellationToken);
}
class _Distinct : AsyncEnumeratorBase<TSource, TSource>
{
readonly HashSet<TKey> set;
readonly Func<TSource, TKey> keySelector;
public _Distinct(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 _DistinctAwait(source, keySelector, comparer, cancellationToken);
}
class _DistinctAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
{
readonly HashSet<TKey> set;
readonly Func<TSource, UniTask<TKey>> keySelector;
public _DistinctAwait(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 DistinctAwaitWithCancellation<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
public DistinctAwaitWithCancellation(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 _DistinctAwaitWithCancellation(source, keySelector, comparer, cancellationToken);
}
class _DistinctAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
{
readonly HashSet<TKey> set;
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
public _DistinctAwaitWithCancellation(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;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f09903be66e5d943b243d7c19cb3811
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,662 @@
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 DistinctUntilChangedAwaitWithCancellation<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 _DistinctUntilChanged(source, comparer, cancellationToken);
}
sealed class _DistinctUntilChanged : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly IEqualityComparer<TSource> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
{
this.source = source;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
var v = enumerator.Current;
if (!comparer.Equals(Current, v))
{
Current = v;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
case -2:
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
}
}
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 _DistinctUntilChanged(source, keySelector, comparer, cancellationToken);
}
sealed class _DistinctUntilChanged : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, TKey> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
TKey prev;
public _DistinctUntilChanged(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
{
this.source = source;
this.keySelector = keySelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
var v = enumerator.Current;
var key = keySelector(v);
if (!comparer.Equals(prev, key))
{
prev = key;
Current = v;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
}
else
{
goto DONE;
}
case -2:
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
}
}
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 _DistinctUntilChangedAwait(source, keySelector, comparer, cancellationToken);
}
sealed class _DistinctUntilChangedAwait : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TKey>.Awaiter awaiter2;
Action moveNextAction;
TSource enumeratorCurrent;
TKey prev;
public _DistinctUntilChangedAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
{
this.source = source;
this.keySelector = keySelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
enumeratorCurrent = enumerator.Current;
awaiter2 = keySelector(enumeratorCurrent).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
var key = awaiter2.GetResult();
if (!comparer.Equals(prev, key))
{
prev = key;
Current = enumeratorCurrent;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
case -2:
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
}
}
internal sealed class DistinctUntilChangedAwaitWithCancellation<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
public DistinctUntilChangedAwaitWithCancellation(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 _DistinctUntilChangedAwaitWithCancellation(source, keySelector, comparer, cancellationToken);
}
sealed class _DistinctUntilChangedAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
readonly IEqualityComparer<TKey> comparer;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TKey>.Awaiter awaiter2;
Action moveNextAction;
TSource enumeratorCurrent;
TKey prev;
public _DistinctUntilChangedAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
{
this.source = source;
this.keySelector = keySelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
REPEAT:
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case -3;
}
else
{
state = -3;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case -3: // first
if (awaiter.GetResult())
{
Current = enumerator.Current;
goto CONTINUE;
}
else
{
goto DONE;
}
case 0: // normal
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
enumeratorCurrent = enumerator.Current;
awaiter2 = keySelector(enumeratorCurrent, cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
var key = awaiter2.GetResult();
if (!comparer.Equals(prev, key))
{
prev = key;
Current = enumeratorCurrent;
goto CONTINUE;
}
else
{
state = 0;
goto REPEAT;
}
case -2:
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0351f6767df7e644b935d4d599968162
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,258 @@
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 _Do(source, onNext, onError, onCompleted, cancellationToken);
}
sealed class _Do : 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 _Do(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_Do)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd83c8e12dedf75409b829b93146d130
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
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.ElementAtAsync(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.ElementAtAsync(source, index, cancellationToken, true);
}
}
internal static class ElementAt
{
public static async UniTask<TSource> ElementAtAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c835bd2dd8555234c8919c7b8ef3b69a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
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 _Empty.Instance;
}
class _Empty : IUniTaskAsyncEnumerator<T>
{
public static readonly IUniTaskAsyncEnumerator<T> Instance = new _Empty();
_Empty()
{
}
public T Current => default;
public UniTask<bool> MoveNextAsync()
{
return CompletedTasks.False;
}
public UniTask DisposeAsync()
{
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4fa123ad6258abb4184721b719a13810
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,116 @@
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 _Except(first, second, comparer, cancellationToken);
}
class _Except : 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 _Except(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 = (_Except)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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38c1c4129f59dcb49a5b864eaf4ec63c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
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.FirstAsync(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.FirstAsync(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.FirstAwaitAsync(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.FirstAwaitWithCancellationAsync(source, predicate, cancellationToken, false);
}
public static UniTask<TSource> FirstOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
return First.FirstAsync(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.FirstAsync(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.FirstAwaitAsync(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.FirstAwaitWithCancellationAsync(source, predicate, cancellationToken, true);
}
}
internal static class First
{
public static async UniTask<TSource> FirstAsync<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> FirstAsync<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> FirstAwaitAsync<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> FirstAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 417946e97e9eed84db6f840f57037ca6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,193 @@
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.ForEachAsync(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.ForEachAsync(source, action, cancellationToken);
}
/// <summary>Obsolete(Error), Use Use ForEachAwaitAsync instead.</summary>
[Obsolete("Use ForEachAwaitAsync instead.", true)]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static UniTask ForEachAsync<T>(this IUniTaskAsyncEnumerable<T> source, Func<T, UniTask> action, CancellationToken cancellationToken = default)
{
throw new NotSupportedException("Use ForEachAwaitAsync instead.");
}
/// <summary>Obsolete(Error), Use Use ForEachAwaitAsync instead.</summary>
[Obsolete("Use ForEachAwaitAsync instead.", true)]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static UniTask ForEachAsync<T>(this IUniTaskAsyncEnumerable<T> source, Func<T, int, UniTask> action, CancellationToken cancellationToken = default)
{
throw new NotSupportedException("Use ForEachAwaitAsync instead.");
}
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.ForEachAwaitAsync(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.ForEachAwaitAsync(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.ForEachAwaitWithCancellationAsync(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.ForEachAwaitWithCancellationAsync(source, action, cancellationToken);
}
}
internal static class ForEach
{
public static async UniTask ForEachAsync<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 ForEachAsync<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 ForEachAwaitAsync<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 ForEachAwaitAsync<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 ForEachAwaitWithCancellationAsync<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 ForEachAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca8d7f8177ba16140920af405aea3fd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,923 @@
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 _GroupBy(source, keySelector, elementSelector, comparer, cancellationToken);
}
sealed class _GroupBy : 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 _GroupBy(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;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
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 _GroupBy(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupBy : 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 _GroupBy(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;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
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 _GroupByAwait(source, keySelector, elementSelector, comparer, cancellationToken);
}
sealed class _GroupByAwait : 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 _GroupByAwait(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;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
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 _GroupByAwait(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupByAwait : 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 _GroupByAwait(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_GroupByAwait)state;
if (self.TryGetResult(self.awaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
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 _GroupByAwaitWithCancellation(source, keySelector, elementSelector, comparer, cancellationToken);
}
sealed class _GroupByAwaitWithCancellation : 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 _GroupByAwaitWithCancellation(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;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
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 _GroupByAwaitWithCancellation(source, keySelector, elementSelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupByAwaitWithCancellation : 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 _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, CancellationToken cancellationToken)
{
this.source = source;
this.keySelector = keySelector;
this.elementSelector = elementSelector;
this.resultSelector = resultSelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_GroupByAwaitWithCancellation)state;
if (self.TryGetResult(self.awaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (groupEnumerator != null)
{
groupEnumerator.Dispose();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2de80df1cc8a1240ab0ee7badd334d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,612 @@
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 GroupJoinAwaitWithCancellation<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 GroupJoinAwaitWithCancellation<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 _GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupJoin : 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 _GroupJoin(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_GroupJoin)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()
{
TaskTracker.RemoveTracking(this);
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 _GroupJoinAwait(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupJoinAwait : 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 _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, CancellationToken cancellationToken)
{
this.outer = outer;
this.inner = inner;
this.outerKeySelector = outerKeySelector;
this.innerKeySelector = innerKeySelector;
this.resultSelector = resultSelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_GroupJoinAwait)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 = (_GroupJoinAwait)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 = (_GroupJoinAwait)state;
if (self.TryGetResult(self.resultAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
internal sealed class GroupJoinAwaitWithCancellation<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 GroupJoinAwaitWithCancellation(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 _GroupJoinAwaitWithCancellation(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _GroupJoinAwaitWithCancellation : 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 _GroupJoinAwaitWithCancellation(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_GroupJoinAwaitWithCancellation)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 = (_GroupJoinAwaitWithCancellation)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 = (_GroupJoinAwaitWithCancellation)state;
if (self.TryGetResult(self.resultAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7bf7759d03bf3f64190d3ae83b182c2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
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 _Intersect(first, second, comparer, cancellationToken);
}
class _Intersect : 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 _Intersect(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 = (_Intersect)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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93999a70f5d57134bbe971f3e988c4f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,728 @@
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 _Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _Join : 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 _Join(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_Join)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()
{
TaskTracker.RemoveTracking(this);
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 _JoinAwait(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _JoinAwait : 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 _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, CancellationToken cancellationToken)
{
this.outer = outer;
this.inner = inner;
this.outerKeySelector = outerKeySelector;
this.innerKeySelector = innerKeySelector;
this.resultSelector = resultSelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_JoinAwait)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 = (_JoinAwait)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 = (_JoinAwait)state;
if (self.TryGetResult(self.resultAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
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 _JoinAwaitWithCancellation(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken);
}
sealed class _JoinAwaitWithCancellation : 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 _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, CancellationToken cancellationToken)
{
this.outer = outer;
this.inner = inner;
this.outerKeySelector = outerKeySelector;
this.innerKeySelector = innerKeySelector;
this.resultSelector = resultSelector;
this.comparer = comparer;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_JoinAwaitWithCancellation)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 = (_JoinAwaitWithCancellation)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 = (_JoinAwaitWithCancellation)state;
if (self.TryGetResult(self.resultAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (valueEnumerator != null)
{
valueEnumerator.Dispose();
}
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc4ff8cb6d7c9a64896f2f082124d6b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,240 @@
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.LastAsync(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.LastAsync(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.LastAwaitAsync(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.LastAwaitWithCancellationAsync(source, predicate, cancellationToken, false);
}
public static UniTask<TSource> LastOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
return Last.LastAsync(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.LastAsync(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.LastAwaitAsync(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.LastAwaitWithCancellationAsync(source, predicate, cancellationToken, true);
}
}
internal static class Last
{
public static async UniTask<TSource> LastAsync<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> LastAsync<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> LastAwaitAsync<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> LastAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0ccc93be1387fa4a975f06310127c11
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,144 @@
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.LongCountAsync(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.LongCountAsync(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.LongCountAwaitAsync(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.LongCountAwaitWithCancellationAsync(source, predicate, cancellationToken);
}
}
internal static class LongCount
{
internal static async UniTask<long> LongCountAsync<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> LongCountAsync<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> LongCountAwaitAsync<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> LongCountAwaitWithCancellationAsync<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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 198b39e58ced3ab4f97ccbe0916787d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
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.MaxAsync(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.MaxAsync(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.MaxAwaitAsync(source, selector, cancellationToken);
}
public static UniTask<TResult> MaxAwaitWithCancellationAsync<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.MaxAwaitWithCancellationAsync(source, selector, cancellationToken);
}
}
internal static partial class Max
{
public static async UniTask<TSource> MaxAsync<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> MaxAsync<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> MaxAwaitAsync<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> MaxAwaitWithCancellationAsync<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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c8a118a6b664c441820b8a87d7f6e28
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
return new Merge<T>(new [] { first, second });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second, IUniTaskAsyncEnumerable<T> third)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(third, nameof(third));
return new Merge<T>(new[] { first, second, third });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
{
return new Merge<T>(sources.ToArray());
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(params IUniTaskAsyncEnumerable<T>[] sources)
{
return new Merge<T>(sources);
}
}
internal sealed class Merge<T> : IUniTaskAsyncEnumerable<T>
{
readonly IUniTaskAsyncEnumerable<T>[] sources;
public Merge(IUniTaskAsyncEnumerable<T>[] sources)
{
if (sources.Length <= 0)
{
Error.ThrowArgumentException("No source async enumerable to merge");
}
this.sources = sources;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new _Merge(sources, cancellationToken);
enum MergeSourceState
{
Pending,
Running,
Completed,
}
sealed class _Merge : MoveNextSource, IUniTaskAsyncEnumerator<T>
{
static readonly Action<object> GetResultAtAction = GetResultAt;
readonly int length;
readonly IUniTaskAsyncEnumerator<T>[] enumerators;
readonly MergeSourceState[] states;
readonly Queue<(T, Exception, bool)> queuedResult = new Queue<(T, Exception, bool)>();
readonly CancellationToken cancellationToken;
int moveNextCompleted;
public T Current { get; private set; }
public _Merge(IUniTaskAsyncEnumerable<T>[] sources, CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
length = sources.Length;
states = ArrayPool<MergeSourceState>.Shared.Rent(length);
enumerators = ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Rent(length);
for (var i = 0; i < length; i++)
{
enumerators[i] = sources[i].GetAsyncEnumerator(cancellationToken);
states[i] = (int)MergeSourceState.Pending;;
}
}
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
completionSource.Reset();
Interlocked.Exchange(ref moveNextCompleted, 0);
if (HasQueuedResult() && Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
(T, Exception, bool) value;
lock (states)
{
value = queuedResult.Dequeue();
}
var resultValue = value.Item1;
var exception = value.Item2;
var hasNext = value.Item3;
if (exception != null)
{
completionSource.TrySetException(exception);
}
else
{
Current = resultValue;
completionSource.TrySetResult(hasNext);
}
return new UniTask<bool>(this, completionSource.Version);
}
for (var i = 0; i < length; i++)
{
lock (states)
{
if (states[i] == MergeSourceState.Pending)
{
states[i] = MergeSourceState.Running;
}
else
{
continue;
}
}
var awaiter = enumerators[i].MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
GetResultAt(i, awaiter);
}
else
{
awaiter.SourceOnCompleted(GetResultAtAction, StateTuple.Create(this, i, awaiter));
}
}
return new UniTask<bool>(this, completionSource.Version);
}
public async UniTask DisposeAsync()
{
for (var i = 0; i < length; i++)
{
await enumerators[i].DisposeAsync();
}
ArrayPool<MergeSourceState>.Shared.Return(states, true);
ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Return(enumerators, true);
}
static void GetResultAt(object state)
{
using (var tuple = (StateTuple<_Merge, int, UniTask<bool>.Awaiter>)state)
{
tuple.Item1.GetResultAt(tuple.Item2, tuple.Item3);
}
}
void GetResultAt(int index, UniTask<bool>.Awaiter awaiter)
{
bool hasNext;
bool completedAll;
try
{
hasNext = awaiter.GetResult();
}
catch (Exception ex)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
completionSource.TrySetException(ex);
}
else
{
lock (states)
{
queuedResult.Enqueue((default, ex, default));
}
}
return;
}
lock (states)
{
states[index] = hasNext ? MergeSourceState.Pending : MergeSourceState.Completed;
completedAll = !hasNext && IsCompletedAll();
}
if (hasNext || completedAll)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
Current = enumerators[index].Current;
completionSource.TrySetResult(!completedAll);
}
else
{
lock (states)
{
queuedResult.Enqueue((enumerators[index].Current, null, !completedAll));
}
}
}
}
bool HasQueuedResult()
{
lock (states)
{
return queuedResult.Count > 0;
}
}
bool IsCompletedAll()
{
lock (states)
{
for (var i = 0; i < length; i++)
{
if (states[i] != MergeSourceState.Completed)
{
return false;
}
}
}
return true;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca56812f160c45d0bacb4339819edf1a
timeCreated: 1694133666

View File

@@ -0,0 +1,200 @@
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.MinAsync(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.MinAsync(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.MinAwaitAsync(source, selector, cancellationToken);
}
public static UniTask<TResult> MinAwaitWithCancellationAsync<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.MinAwaitWithCancellationAsync(source, selector, cancellationToken);
}
}
internal static partial class Min
{
public static async UniTask<TSource> MinAsync<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> MinAsync<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> MinAwaitAsync<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> MinAwaitWithCancellationAsync<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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57ac9da21d3457849a8e45548290a508
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2d6da02d9ab970e4999daf7147d98e36
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
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 _Never(cancellationToken);
}
class _Never : IUniTaskAsyncEnumerator<T>
{
CancellationToken cancellationToken;
public _Never(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b307c3d3be71a94da251564bcdefa3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
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 _OfType(source, cancellationToken);
}
class _OfType : AsyncEnumeratorBase<object, TResult>
{
public _OfType(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 111ffe87a7d700442a9ef5af554b252c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,558 @@
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 _OrderedAsyncEnumerator(this, cancellationToken);
}
class _OrderedAsyncEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<TElement>
{
protected readonly OrderedAsyncEnumerable<TElement> parent;
CancellationToken cancellationToken;
TElement[] buffer;
int[] map;
int index;
public _OrderedAsyncEnumerator(OrderedAsyncEnumerable<TElement> parent, CancellationToken cancellationToken)
{
this.parent = parent;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 413883ceff8546143bdf200aafa4b8f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,128 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<(TSource, TSource)> Pairwise<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
{
Error.ThrowArgumentNullException(source, nameof(source));
return new Pairwise<TSource>(source);
}
}
internal sealed class Pairwise<TSource> : IUniTaskAsyncEnumerable<(TSource, TSource)>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
public Pairwise(IUniTaskAsyncEnumerable<TSource> source)
{
this.source = source;
}
public IUniTaskAsyncEnumerator<(TSource, TSource)> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Pairwise(source, cancellationToken);
}
sealed class _Pairwise : MoveNextSource, IUniTaskAsyncEnumerator<(TSource, TSource)>
{
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
TSource prev;
bool isFirst;
public _Pairwise(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
{
this.source = source;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
public (TSource, TSource) Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
if (enumerator == null)
{
isFirst = true;
enumerator = source.GetAsyncEnumerator(cancellationToken);
}
completionSource.Reset();
SourceMoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
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 = (_Pairwise)state;
if (self.TryGetResult(self.awaiter, out var result))
{
if (result)
{
if (self.isFirst)
{
self.isFirst = false;
self.prev = self.enumerator.Current;
self.SourceMoveNext(); // run again. okay to use recursive(only one more).
}
else
{
var p = self.prev;
self.prev = self.enumerator.Current;
self.Current = (p, self.prev);
self.completionSource.TrySetResult(true);
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cddbf051d2a88f549986c468b23214af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IConnectableUniTaskAsyncEnumerable<TSource> Publish<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
{
Error.ThrowArgumentNullException(source, nameof(source));
return new Publish<TSource>(source);
}
}
internal sealed class Publish<TSource> : IConnectableUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly CancellationTokenSource cancellationTokenSource;
TriggerEvent<TSource> trigger;
IUniTaskAsyncEnumerator<TSource> enumerator;
IDisposable connectedDisposable;
bool isCompleted;
public Publish(IUniTaskAsyncEnumerable<TSource> source)
{
this.source = source;
this.cancellationTokenSource = new CancellationTokenSource();
}
public IDisposable Connect()
{
if (connectedDisposable != null) return connectedDisposable;
if (enumerator == null)
{
enumerator = source.GetAsyncEnumerator(cancellationTokenSource.Token);
}
ConsumeEnumerator().Forget();
connectedDisposable = new ConnectDisposable(cancellationTokenSource);
return connectedDisposable;
}
async UniTaskVoid ConsumeEnumerator()
{
try
{
try
{
while (await enumerator.MoveNextAsync())
{
trigger.SetResult(enumerator.Current);
}
trigger.SetCompleted();
}
catch (Exception ex)
{
trigger.SetError(ex);
}
}
finally
{
isCompleted = true;
await enumerator.DisposeAsync();
}
}
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Publish(this, cancellationToken);
}
sealed class ConnectDisposable : IDisposable
{
readonly CancellationTokenSource cancellationTokenSource;
public ConnectDisposable(CancellationTokenSource cancellationTokenSource)
{
this.cancellationTokenSource = cancellationTokenSource;
}
public void Dispose()
{
this.cancellationTokenSource.Cancel();
}
}
sealed class _Publish : MoveNextSource, IUniTaskAsyncEnumerator<TSource>, ITriggerHandler<TSource>
{
static readonly Action<object> CancelDelegate = OnCanceled;
readonly Publish<TSource> parent;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool isDisposed;
public _Publish(Publish<TSource> parent, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested) return;
this.parent = parent;
this.cancellationToken = cancellationToken;
if (cancellationToken.CanBeCanceled)
{
this.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancelDelegate, this);
}
parent.trigger.Add(this);
TaskTracker.TrackActiveTask(this, 3);
}
public TSource Current { get; private set; }
ITriggerHandler<TSource> ITriggerHandler<TSource>.Prev { get; set; }
ITriggerHandler<TSource> ITriggerHandler<TSource>.Next { get; set; }
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
if (parent.isCompleted) return CompletedTasks.False;
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
static void OnCanceled(object state)
{
var self = (_Publish)state;
self.completionSource.TrySetCanceled(self.cancellationToken);
self.DisposeAsync().Forget();
}
public UniTask DisposeAsync()
{
if (!isDisposed)
{
isDisposed = true;
TaskTracker.RemoveTracking(this);
cancellationTokenRegistration.Dispose();
parent.trigger.Remove(this);
}
return default;
}
public void OnNext(TSource value)
{
Current = value;
completionSource.TrySetResult(true);
}
public void OnCanceled(CancellationToken cancellationToken)
{
completionSource.TrySetCanceled(cancellationToken);
}
public void OnCompleted()
{
completionSource.TrySetResult(false);
}
public void OnError(Exception ex)
{
completionSource.TrySetException(ex);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93c684d1e88c09d4e89b79437d97b810
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,103 @@
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TSource> Queue<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
{
return new QueueOperator<TSource>(source);
}
}
internal sealed class QueueOperator<TSource> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
public QueueOperator(IUniTaskAsyncEnumerable<TSource> source)
{
this.source = source;
}
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Queue(source, cancellationToken);
}
sealed class _Queue : IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken;
Channel<TSource> channel;
IUniTaskAsyncEnumerator<TSource> channelEnumerator;
IUniTaskAsyncEnumerator<TSource> sourceEnumerator;
bool channelClosed;
public _Queue(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
{
this.source = source;
this.cancellationToken = cancellationToken;
}
public TSource Current => channelEnumerator.Current;
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
if (sourceEnumerator == null)
{
sourceEnumerator = source.GetAsyncEnumerator(cancellationToken);
channel = Channel.CreateSingleConsumerUnbounded<TSource>();
channelEnumerator = channel.Reader.ReadAllAsync().GetAsyncEnumerator(cancellationToken);
ConsumeAll(this, sourceEnumerator, channel).Forget();
}
return channelEnumerator.MoveNextAsync();
}
static async UniTaskVoid ConsumeAll(_Queue self, IUniTaskAsyncEnumerator<TSource> enumerator, ChannelWriter<TSource> writer)
{
try
{
while (await enumerator.MoveNextAsync())
{
writer.TryWrite(enumerator.Current);
}
writer.TryComplete();
}
catch (Exception ex)
{
writer.TryComplete(ex);
}
finally
{
self.channelClosed = true;
await enumerator.DisposeAsync();
}
}
public async UniTask DisposeAsync()
{
if (sourceEnumerator != null)
{
await sourceEnumerator.DisposeAsync();
}
if (channelEnumerator != null)
{
await channelEnumerator.DisposeAsync();
}
if (!channelClosed)
{
channelClosed = true;
channel.Writer.TryComplete(new OperationCanceledException());
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7ea1bcf9dbebb042bc99c7816249e02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
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 _Range(start, end, cancellationToken);
}
class _Range : IUniTaskAsyncEnumerator<int>
{
readonly int start;
readonly int end;
int current;
CancellationToken cancellationToken;
public _Range(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d826418a813498648b10542d0a5fb173
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
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 _Repeat(element, count, cancellationToken);
}
class _Repeat : IUniTaskAsyncEnumerator<TElement>
{
readonly TElement element;
readonly int count;
int remaining;
CancellationToken cancellationToken;
public _Repeat(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3819a3925165a674d80ee848c8600379
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
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 _Return(value, cancellationToken);
}
class _Return : IUniTaskAsyncEnumerator<TValue>
{
readonly TValue value;
CancellationToken cancellationToken;
bool called;
public _Return(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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4313cd8ecf705e44f9064ce46e293c2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
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 _Reverse(source, cancellationToken);
}
sealed class _Reverse : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken;
TSource[] array;
int index;
public _Reverse(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
{
this.source = source;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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()
{
TaskTracker.RemoveTracking(this);
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2769e65c729b4f4ca6af9826d9c7b90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,760 @@
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.SelectIntAwait<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.SelectAwaitWithCancellation<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.SelectIntAwaitWithCancellation<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 _Select(source, selector, cancellationToken);
}
sealed class _Select : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, TResult> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
public _Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TResult> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = selector(enumerator.Current);
goto CONTINUE;
}
else
{
goto DONE;
}
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
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 _Select(source, selector, cancellationToken);
}
sealed class _Select : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, TResult> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
Action moveNextAction;
int index;
public _Select(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
Current = selector(enumerator.Current, checked(index++));
goto CONTINUE;
}
else
{
goto DONE;
}
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
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 _SelectAwait(source, selector, cancellationToken);
}
sealed class _SelectAwait : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
public _SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TResult>> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
internal sealed class SelectIntAwait<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, UniTask<TResult>> selector;
public SelectIntAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector)
{
this.source = source;
this.selector = selector;
}
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _SelectAwait(source, selector, cancellationToken);
}
sealed class _SelectAwait : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
int index;
public _SelectAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, UniTask<TResult>> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, checked(index++)).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
internal sealed class SelectAwaitWithCancellation<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TResult>> selector;
public SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector)
{
this.source = source;
this.selector = selector;
}
public IUniTaskAsyncEnumerator<TResult> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _SelectAwaitWithCancellation(source, selector, cancellationToken);
}
sealed class _SelectAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, CancellationToken, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
public _SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
internal sealed class SelectIntAwaitWithCancellation<TSource, TResult> : IUniTaskAsyncEnumerable<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector;
public SelectIntAwaitWithCancellation(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 _SelectAwaitWithCancellation(source, selector, cancellationToken);
}
sealed class _SelectAwaitWithCancellation : MoveNextSource, IUniTaskAsyncEnumerator<TResult>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly Func<TSource, int, CancellationToken, UniTask<TResult>> selector;
readonly CancellationToken cancellationToken;
int state = -1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
UniTask<TResult>.Awaiter awaiter2;
Action moveNextAction;
int index;
public _SelectAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, UniTask<TResult>> selector, CancellationToken cancellationToken)
{
this.source = source;
this.selector = selector;
this.cancellationToken = cancellationToken;
this.moveNextAction = MoveNext;
TaskTracker.TrackActiveTask(this, 3);
}
public TResult Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (state == -2) return default;
completionSource.Reset();
MoveNext();
return new UniTask<bool>(this, completionSource.Version);
}
void MoveNext()
{
try
{
switch (state)
{
case -1: // init
enumerator = source.GetAsyncEnumerator(cancellationToken);
goto case 0;
case 0:
awaiter = enumerator.MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
goto case 1;
}
else
{
state = 1;
awaiter.UnsafeOnCompleted(moveNextAction);
return;
}
case 1:
if (awaiter.GetResult())
{
awaiter2 = selector(enumerator.Current, checked(index++), cancellationToken).GetAwaiter();
if (awaiter2.IsCompleted)
{
goto case 2;
}
else
{
state = 2;
awaiter2.UnsafeOnCompleted(moveNextAction);
return;
}
}
else
{
goto DONE;
}
case 2:
Current = awaiter2.GetResult();
goto CONTINUE;
default:
goto DONE;
}
}
catch (Exception ex)
{
state = -2;
completionSource.TrySetException(ex);
return;
}
DONE:
state = -2;
completionSource.TrySetResult(false);
return;
CONTINUE:
state = 0;
completionSource.TrySetResult(true);
return;
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
return enumerator.DisposeAsync();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc68e598ca44a134b988dfaf5e53bfba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,892 @@
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 _SelectMany(source, selector1, selector2, resultSelector, cancellationToken);
}
sealed class _SelectMany : 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 _SelectMany(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_SelectMany)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 = (_SelectMany)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 = (_SelectMany)state;
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
{
self.selectedEnumerator = null;
self.selectedAwaiter = default;
self.MoveNextSource(); // iterate next source
}
}
public async UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
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 _SelectManyAwait(source, selector1, selector2, resultSelector, cancellationToken);
}
sealed class _SelectManyAwait : 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 _SelectManyAwait(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_SelectManyAwait)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 = (_SelectManyAwait)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 = (_SelectManyAwait)state;
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
{
self.selectedEnumerator = null;
self.selectedAwaiter = default;
self.MoveNextSource(); // iterate next source
}
}
static void SelectorAwaitCore(object state)
{
var self = (_SelectManyAwait)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 = (_SelectManyAwait)state;
if (self.TryGetResult(self.resultSelectorAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public async UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
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 _SelectManyAwaitWithCancellation(source, selector1, selector2, resultSelector, cancellationToken);
}
sealed class _SelectManyAwaitWithCancellation : 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 _SelectManyAwaitWithCancellation(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;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_SelectManyAwaitWithCancellation)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 = (_SelectManyAwaitWithCancellation)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 = (_SelectManyAwaitWithCancellation)state;
if (self.TryGetResult(self.selectedDisposeAsyncAwaiter))
{
self.selectedEnumerator = null;
self.selectedAwaiter = default;
self.MoveNextSource(); // iterate next source
}
}
static void SelectorAwaitCore(object state)
{
var self = (_SelectManyAwaitWithCancellation)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 = (_SelectManyAwaitWithCancellation)state;
if (self.TryGetResult(self.resultSelectorAwaiter, out var result))
{
self.Current = result;
self.completionSource.TrySetResult(true);
}
}
public async UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
if (selectedEnumerator != null)
{
await selectedEnumerator.DisposeAsync();
}
if (sourceEnumerator != null)
{
await sourceEnumerator.DisposeAsync();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d81862f0eb12680479ccaaf2ac319d24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
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.SequenceEqualAsync(first, second, comparer, cancellationToken);
}
}
internal static class SequenceEqual
{
internal static async UniTask<bool> SequenceEqualAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b382772aba6128842928cdb6b2e034b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,230 @@
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.SingleAsync(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.SingleAsync(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.SingleAwaitAsync(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.SingleAwaitWithCancellationAsync(source, predicate, cancellationToken, false);
}
public static UniTask<TSource> SingleOrDefaultAsync<TSource>(this IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
{
Error.ThrowArgumentNullException(source, nameof(source));
return SingleOperator.SingleAsync(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.SingleAsync(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.SingleAwaitAsync(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.SingleAwaitWithCancellationAsync(source, predicate, cancellationToken, true);
}
}
internal static class SingleOperator
{
public static async UniTask<TSource> SingleAsync<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> SingleAsync<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> SingleAwaitAsync<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> SingleAwaitWithCancellationAsync<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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1bcd3928b90472e43a3a92c3ba708967
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
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 _Skip(source, count, cancellationToken);
}
sealed class _Skip : AsyncEnumeratorBase<TSource, TSource>
{
readonly int count;
int index;
public _Skip(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;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c46b6c7dce0cb049a73c81084c75154
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,159 @@
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 _SkipLast(source, count, cancellationToken);
}
sealed class _SkipLast : 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 _SkipLast(IUniTaskAsyncEnumerable<TSource> source, int count, CancellationToken cancellationToken)
{
this.source = source;
this.count = count;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 3);
}
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 = (_SkipLast)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()
{
TaskTracker.RemoveTracking(this);
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df1d7f44d4fe7754f972c9e0b6fa72d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,187 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
{
Error.ThrowArgumentNullException(source, nameof(source));
return new SkipUntil<TSource>(source, other, null);
}
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(source, nameof(other));
return new SkipUntil<TSource>(source, default, other);
}
}
internal sealed class SkipUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
{
readonly IUniTaskAsyncEnumerable<TSource> source;
readonly UniTask other;
readonly Func<CancellationToken, UniTask> other2;
public SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
{
this.source = source;
this.other = other;
this.other2 = other2;
}
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
if (other2 != null)
{
return new _SkipUntil(source, this.other2(cancellationToken), cancellationToken);
}
else
{
return new _SkipUntil(source, this.other, cancellationToken);
}
}
sealed class _SkipUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
{
static readonly Action<object> CancelDelegate1 = OnCanceled1;
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
readonly IUniTaskAsyncEnumerable<TSource> source;
CancellationToken cancellationToken1;
bool completed;
CancellationTokenRegistration cancellationTokenRegistration1;
IUniTaskAsyncEnumerator<TSource> enumerator;
UniTask<bool>.Awaiter awaiter;
bool continueNext;
Exception exception;
public _SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
{
this.source = source;
this.cancellationToken1 = cancellationToken1;
if (cancellationToken1.CanBeCanceled)
{
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
}
TaskTracker.TrackActiveTask(this, 3);
RunOther(other).Forget();
}
public TSource Current { get; private set; }
public UniTask<bool> MoveNextAsync()
{
if (exception != null)
{
return UniTask.FromException<bool>(exception);
}
if (cancellationToken1.IsCancellationRequested)
{
return UniTask.FromCanceled<bool>(cancellationToken1);
}
if (enumerator == null)
{
enumerator = source.GetAsyncEnumerator(cancellationToken1);
}
completionSource.Reset();
if (completed)
{
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;
}
}
else
{
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
}
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void MoveNextCore(object state)
{
var self = (_SkipUntil)state;
if (self.TryGetResult(self.awaiter, out var result))
{
if (result)
{
self.Current = self.enumerator.Current;
self.completionSource.TrySetResult(true);
if (self.continueNext)
{
self.SourceMoveNext();
}
}
else
{
self.completionSource.TrySetResult(false);
}
}
}
async UniTaskVoid RunOther(UniTask other)
{
try
{
await other;
completed = true;
SourceMoveNext();
}
catch (Exception ex)
{
exception = ex;
completionSource.TrySetException(ex);
}
}
static void OnCanceled1(object state)
{
var self = (_SkipUntil)state;
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
cancellationTokenRegistration1.Dispose();
if (enumerator != null)
{
return enumerator.DisposeAsync();
}
return default;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de932d79c8d9f3841a066d05ff29edc9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More