diff --git a/src/UniTask.NetCore/IAsyncEnumerable.cs b/src/UniTask.NetCore/IAsyncEnumerable.cs index 917c521..757333d 100644 --- a/src/UniTask.NetCore/IAsyncEnumerable.cs +++ b/src/UniTask.NetCore/IAsyncEnumerable.cs @@ -1,4 +1,6 @@ -using System.Runtime.InteropServices; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading; namespace Cysharp.Threading.Tasks @@ -19,6 +21,11 @@ namespace Cysharp.Threading.Tasks UniTask DisposeAsync(); } + public interface IUniTaskOrderedAsyncEnumerable : IUniTaskAsyncEnumerable + { + IUniTaskOrderedAsyncEnumerable CreateOrderedEnumerable(Func keySelector, IComparer comparer, bool descending); + } + //public interface IUniTaskAsyncGrouping : IUniTaskAsyncEnumerable //{ // TKey Key { get; } diff --git a/src/UniTask.NetCore/Linq/GroupBy.cs b/src/UniTask.NetCore/Linq/GroupBy.cs index 5da393b..d3fb03c 100644 --- a/src/UniTask.NetCore/Linq/GroupBy.cs +++ b/src/UniTask.NetCore/Linq/GroupBy.cs @@ -12,40 +12,68 @@ namespace Cysharp.Threading.Tasks.Linq public static IUniTaskAsyncEnumerable> GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); return new GroupBy(source, keySelector, x => x, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupBy(source, keySelector, x => x, comparer); } public static IUniTaskAsyncEnumerable> GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func elementSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); return new GroupBy(source, keySelector, elementSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupBy(source, keySelector, elementSelector, comparer); } public static IUniTaskAsyncEnumerable GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func, TResult> resultSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); return new GroupBy(source, keySelector, x => x, resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupBy(source, keySelector, x => x, resultSelector, comparer); } public static IUniTaskAsyncEnumerable GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func elementSelector, Func, 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(source, keySelector, elementSelector, resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupBy(this IUniTaskAsyncEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer 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(source, keySelector, elementSelector, resultSelector, comparer); } @@ -53,41 +81,69 @@ namespace Cysharp.Threading.Tasks.Linq public static IUniTaskAsyncEnumerable> GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); return new GroupByAwait(source, keySelector, x => UniTask.FromResult(x), EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwait(source, keySelector, x => UniTask.FromResult(x), comparer); } public static IUniTaskAsyncEnumerable> GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); return new GroupByAwait(source, keySelector, elementSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwait(source, keySelector, elementSelector, comparer); } public static IUniTaskAsyncEnumerable GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func, UniTask> resultSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); return new GroupByAwait(source, keySelector, x => UniTask.FromResult(x), resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, Func, UniTask> resultSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); return new GroupByAwait(source, keySelector, elementSelector, resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func, UniTask> resultSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwait(source, keySelector, x => UniTask.FromResult(x), resultSelector, comparer); } public static IUniTaskAsyncEnumerable GroupByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, Func, UniTask> resultSelector, IEqualityComparer 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(source, keySelector, elementSelector, resultSelector, comparer); } @@ -95,41 +151,69 @@ namespace Cysharp.Threading.Tasks.Linq public static IUniTaskAsyncEnumerable> GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); return new GroupByAwaitWithCancellation(source, keySelector, (x, _) => UniTask.FromResult(x), EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwaitWithCancellation(source, keySelector, (x, _) => UniTask.FromResult(x), comparer); } public static IUniTaskAsyncEnumerable> GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); return new GroupByAwaitWithCancellation(source, keySelector, elementSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable> GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwaitWithCancellation(source, keySelector, elementSelector, comparer); } public static IUniTaskAsyncEnumerable GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func, CancellationToken, UniTask> resultSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); return new GroupByAwaitWithCancellation(source, keySelector, (x, _) => UniTask.FromResult(x), resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, Func, CancellationToken, UniTask> resultSelector) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(elementSelector, nameof(elementSelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); return new GroupByAwaitWithCancellation(source, keySelector, elementSelector, resultSelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer comparer) { + Error.ThrowArgumentNullException(source, nameof(source)); + Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new GroupByAwaitWithCancellation(source, keySelector, (x, _) => UniTask.FromResult(x), resultSelector, comparer); } public static IUniTaskAsyncEnumerable GroupByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, Func> elementSelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer 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(source, keySelector, elementSelector, resultSelector, comparer); } } diff --git a/src/UniTask.NetCore/Linq/GroupJoin.cs b/src/UniTask.NetCore/Linq/GroupJoin.cs index ddaeaf7..1978ac2 100644 --- a/src/UniTask.NetCore/Linq/GroupJoin.cs +++ b/src/UniTask.NetCore/Linq/GroupJoin.cs @@ -1,775 +1,606 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks.Internal; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class GroupJoin + public static partial class UniTaskAsyncEnumerable { + public static IUniTaskAsyncEnumerable GroupJoin(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, 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(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer.Default); + } + + public static IUniTaskAsyncEnumerable GroupJoin(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer 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(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + public static IUniTaskAsyncEnumerable GroupJoinAwait(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> 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(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer.Default); + } + + public static IUniTaskAsyncEnumerable GroupJoinAwait(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> resultSelector, IEqualityComparer 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(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + public static IUniTaskAsyncEnumerable GroupJoinAwaitWithCancellation(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector) + { + Error.ThrowArgumentNullException(outer, nameof(outer)); + Error.ThrowArgumentNullException(inner, nameof(inner)); + Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector)); + Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + + return new GroupJoinWithCancellationAwait(outer, inner, outerKeySelector, innerKeySelector, resultSelector, EqualityComparer.Default); + } + + public static IUniTaskAsyncEnumerable GroupJoinAwaitWithCancellation(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer comparer) + { + Error.ThrowArgumentNullException(outer, nameof(outer)); + Error.ThrowArgumentNullException(inner, nameof(inner)); + Error.ThrowArgumentNullException(outerKeySelector, nameof(outerKeySelector)); + Error.ThrowArgumentNullException(innerKeySelector, nameof(innerKeySelector)); + Error.ThrowArgumentNullException(resultSelector, nameof(resultSelector)); + Error.ThrowArgumentNullException(comparer, nameof(comparer)); + + return new GroupJoinWithCancellationAwait(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + } - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + internal sealed class GroupJoin : IUniTaskAsyncEnumerable + { + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func outerKeySelector; + readonly Func innerKeySelector; + readonly Func, TResult> resultSelector; + readonly IEqualityComparer comparer; + + public GroupJoin(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + } + + public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken); + } + + sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator + { + static readonly Action MoveNextCoreDelegate = MoveNextCore; + + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func outerKeySelector; + readonly Func innerKeySelector; + readonly Func, TResult> resultSelector; + readonly IEqualityComparer comparer; + CancellationToken cancellationToken; + + ILookup lookup; + IUniTaskAsyncEnumerator enumerator; + UniTask.Awaiter awaiter; + + + public Enumerator(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer, CancellationToken cancellationToken) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + this.cancellationToken = cancellationToken; + } + + public TResult Current { get; private set; } + + public UniTask MoveNextAsync() + { + cancellationToken.ThrowIfCancellationRequested(); + completionSource.Reset(); + + if (lookup == null) + { + CreateLookup().Forget(); + } + else + { + SourceMoveNext(); + } + return new UniTask(this, completionSource.Version); + } + + async UniTaskVoid CreateLookup() + { + try + { + lookup = await inner.ToLookupAsync(innerKeySelector, comparer, cancellationToken); + enumerator = outer.GetAsyncEnumerator(cancellationToken); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + return; + } + SourceMoveNext(); + } + + void SourceMoveNext() + { + try + { + awaiter = enumerator.MoveNextAsync().GetAwaiter(); + if (awaiter.IsCompleted) + { + MoveNextCore(this); + } + else + { + awaiter.SourceOnCompleted(MoveNextCoreDelegate, this); + } + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + } + + static void MoveNextCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.awaiter, out var result)) + { + if (result) + { + var outer = self.enumerator.Current; + var key = self.outerKeySelector(outer); + var values = self.lookup[key]; + + self.Current = self.resultSelector(outer, values); + self.completionSource.TrySetResult(true); + } + else + { + self.completionSource.TrySetResult(false); + } + } + } + + public UniTask DisposeAsync() + { + if (enumerator != null) + { + return enumerator.DisposeAsync(); + } + + return default; + } + } + } + + internal sealed class GroupJoinAwait : IUniTaskAsyncEnumerable + { + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func> outerKeySelector; + readonly Func> innerKeySelector; + readonly Func, UniTask> resultSelector; + readonly IEqualityComparer comparer; + + public GroupJoinAwait(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> resultSelector, IEqualityComparer comparer) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + } + + public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken); + } + + sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator + { + static readonly Action MoveNextCoreDelegate = MoveNextCore; + readonly static Action ResultSelectCoreDelegate = ResultSelectCore; + readonly static Action OuterKeySelectCoreDelegate = OuterKeySelectCore; + + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func> outerKeySelector; + readonly Func> innerKeySelector; + readonly Func, UniTask> resultSelector; + readonly IEqualityComparer comparer; + CancellationToken cancellationToken; + + ILookup lookup; + IUniTaskAsyncEnumerator enumerator; + TOuter outerValue; + UniTask.Awaiter awaiter; + UniTask.Awaiter outerKeyAwaiter; + UniTask.Awaiter resultAwaiter; + + + public Enumerator(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> resultSelector, IEqualityComparer comparer, CancellationToken cancellationToken) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + this.cancellationToken = cancellationToken; + } + + public TResult Current { get; private set; } + + public UniTask MoveNextAsync() + { + cancellationToken.ThrowIfCancellationRequested(); + completionSource.Reset(); + + if (lookup == null) + { + CreateLookup().Forget(); + } + else + { + SourceMoveNext(); + } + return new UniTask(this, completionSource.Version); + } + + async UniTaskVoid CreateLookup() + { + try + { + lookup = await inner.ToLookupAwaitAsync(innerKeySelector, comparer, cancellationToken); + enumerator = outer.GetAsyncEnumerator(cancellationToken); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + return; + } + SourceMoveNext(); + } + + void SourceMoveNext() + { + try + { + awaiter = enumerator.MoveNextAsync().GetAwaiter(); + if (awaiter.IsCompleted) + { + MoveNextCore(this); + } + else + { + awaiter.SourceOnCompleted(MoveNextCoreDelegate, this); + } + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + } + + static void MoveNextCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.awaiter, out var result)) + { + if (result) + { + try + { + + self.outerValue = self.enumerator.Current; + self.outerKeyAwaiter = self.outerKeySelector(self.outerValue).GetAwaiter(); + if (self.outerKeyAwaiter.IsCompleted) + { + OuterKeySelectCore(self); + } + else + { + self.outerKeyAwaiter.SourceOnCompleted(OuterKeySelectCoreDelegate, self); + } + } + catch (Exception ex) + { + self.completionSource.TrySetException(ex); + } + } + else + { + self.completionSource.TrySetResult(false); + } + } + } + + static void OuterKeySelectCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.outerKeyAwaiter, out var result)) + { + try + { + var values = self.lookup[result]; + self.resultAwaiter = self.resultSelector(self.outerValue, values).GetAwaiter(); + if (self.resultAwaiter.IsCompleted) + { + ResultSelectCore(self); + } + else + { + self.resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, self); + } + } + catch (Exception ex) + { + self.completionSource.TrySetException(ex); + } + } + } + + static void ResultSelectCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.resultAwaiter, out var result)) + { + self.Current = result; + self.completionSource.TrySetResult(true); + } + } + + public UniTask DisposeAsync() + { + if (enumerator != null) + { + return enumerator.DisposeAsync(); + } + + return default; + } + } + } + + internal sealed class GroupJoinWithCancellationAwait : IUniTaskAsyncEnumerable + { + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func> outerKeySelector; + readonly Func> innerKeySelector; + readonly Func, CancellationToken, UniTask> resultSelector; + readonly IEqualityComparer comparer; + + public GroupJoinWithCancellationAwait(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer comparer) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + } + + public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + return new Enumerator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer, cancellationToken); + } + + sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator + { + static readonly Action MoveNextCoreDelegate = MoveNextCore; + readonly static Action ResultSelectCoreDelegate = ResultSelectCore; + readonly static Action OuterKeySelectCoreDelegate = OuterKeySelectCore; + + readonly IUniTaskAsyncEnumerable outer; + readonly IUniTaskAsyncEnumerable inner; + readonly Func> outerKeySelector; + readonly Func> innerKeySelector; + readonly Func, CancellationToken, UniTask> resultSelector; + readonly IEqualityComparer comparer; + CancellationToken cancellationToken; + + ILookup lookup; + IUniTaskAsyncEnumerator enumerator; + TOuter outerValue; + UniTask.Awaiter awaiter; + UniTask.Awaiter outerKeyAwaiter; + UniTask.Awaiter resultAwaiter; + + + public Enumerator(IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer comparer, CancellationToken cancellationToken) + { + this.outer = outer; + this.inner = inner; + this.outerKeySelector = outerKeySelector; + this.innerKeySelector = innerKeySelector; + this.resultSelector = resultSelector; + this.comparer = comparer; + this.cancellationToken = cancellationToken; + } + + public TResult Current { get; private set; } + + public UniTask MoveNextAsync() + { + cancellationToken.ThrowIfCancellationRequested(); + completionSource.Reset(); + + if (lookup == null) + { + CreateLookup().Forget(); + } + else + { + SourceMoveNext(); + } + return new UniTask(this, completionSource.Version); + } + + async UniTaskVoid CreateLookup() + { + try + { + lookup = await inner.ToLookupAwaitWithCancellationAsync(innerKeySelector, comparer, cancellationToken); + enumerator = outer.GetAsyncEnumerator(cancellationToken); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + return; + } + SourceMoveNext(); + } + + void SourceMoveNext() + { + try + { + awaiter = enumerator.MoveNextAsync().GetAwaiter(); + if (awaiter.IsCompleted) + { + MoveNextCore(this); + } + else + { + awaiter.SourceOnCompleted(MoveNextCoreDelegate, this); + } + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + } + + static void MoveNextCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.awaiter, out var result)) + { + if (result) + { + try + { + + self.outerValue = self.enumerator.Current; + self.outerKeyAwaiter = self.outerKeySelector(self.outerValue, self.cancellationToken).GetAwaiter(); + if (self.outerKeyAwaiter.IsCompleted) + { + OuterKeySelectCore(self); + } + else + { + self.outerKeyAwaiter.SourceOnCompleted(OuterKeySelectCoreDelegate, self); + } + } + catch (Exception ex) + { + self.completionSource.TrySetException(ex); + } + } + else + { + self.completionSource.TrySetResult(false); + } + } + } + + static void OuterKeySelectCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.outerKeyAwaiter, out var result)) + { + try + { + var values = self.lookup[result]; + self.resultAwaiter = self.resultSelector(self.outerValue, values, self.cancellationToken).GetAwaiter(); + if (self.resultAwaiter.IsCompleted) + { + ResultSelectCore(self); + } + else + { + self.resultAwaiter.SourceOnCompleted(ResultSelectCoreDelegate, self); + } + } + catch (Exception ex) + { + self.completionSource.TrySetException(ex); + } + } + } + + static void ResultSelectCore(object state) + { + var self = (Enumerator)state; + + if (self.TryGetResult(self.resultAwaiter, out var result)) + { + self.Current = result; + self.completionSource.TrySetResult(true); + } + } + + public UniTask DisposeAsync() + { + if (enumerator != null) + { + return enumerator.DisposeAsync(); + } + + return default; + } + } + } +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/Join.cs b/src/UniTask.NetCore/Linq/Join.cs index ceebbc8..bfdf779 100644 --- a/src/UniTask.NetCore/Linq/Join.cs +++ b/src/UniTask.NetCore/Linq/Join.cs @@ -129,6 +129,7 @@ namespace Cysharp.Threading.Tasks.Linq this.outerKeySelector = outerKeySelector; this.innerKeySelector = innerKeySelector; this.resultSelector = resultSelector; + this.comparer = comparer; this.cancellationToken = cancellationToken; } @@ -318,6 +319,7 @@ namespace Cysharp.Threading.Tasks.Linq this.outerKeySelector = outerKeySelector; this.innerKeySelector = innerKeySelector; this.resultSelector = resultSelector; + this.comparer = comparer; this.cancellationToken = cancellationToken; } @@ -545,6 +547,7 @@ namespace Cysharp.Threading.Tasks.Linq this.outerKeySelector = outerKeySelector; this.innerKeySelector = innerKeySelector; this.resultSelector = resultSelector; + this.comparer = comparer; this.cancellationToken = cancellationToken; } diff --git a/src/UniTask.NetCore/Linq/OrderBy.cs b/src/UniTask.NetCore/Linq/OrderBy.cs index e661ad2..8bca66f 100644 --- a/src/UniTask.NetCore/Linq/OrderBy.cs +++ b/src/UniTask.NetCore/Linq/OrderBy.cs @@ -1,775 +1,141 @@ -namespace Cysharp.Threading.Tasks.Linq +using Cysharp.Threading.Tasks; +using Cysharp.Threading.Tasks.Internal; +using Cysharp.Threading.Tasks.Linq; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Cysharp.Threading.Tasks.Linq { - internal sealed class OrderBy + public static partial class UniTaskAsyncEnumerable { + #region OrderBy_OrderByDescending + + public static IUniTaskOrderedAsyncEnumerable OrderBy(this IUniTaskAsyncEnumerable source, Func keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderBy(this IUniTaskAsyncEnumerable source, Func keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescending(this IUniTaskAsyncEnumerable source, Func keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescending(this IUniTaskAsyncEnumerable source, Func keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescendingAwait(this IUniTaskAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescendingAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescendingAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable OrderByDescendingAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + #endregion + + #region ThenBy_ThenByDescending + + public static IUniTaskOrderedAsyncEnumerable ThenBy(this IUniTaskOrderedAsyncEnumerable source, Func keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenBy(this IUniTaskOrderedAsyncEnumerable source, Func keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByAwait(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByAwait(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByAwaitWithCancellation(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByAwaitWithCancellation(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescending(this IUniTaskOrderedAsyncEnumerable source, Func keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescending(this IUniTaskOrderedAsyncEnumerable source, Func keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescendingAwait(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescendingAwait(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescendingAwaitWithCancellation(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector) + { + throw new NotImplementedException(); + } + + public static IUniTaskOrderedAsyncEnumerable ThenByDescendingAwaitWithCancellation(this IUniTaskOrderedAsyncEnumerable source, Func> keySelector, IComparer comparer) + { + throw new NotImplementedException(); + } + + #endregion } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/OrderByDescending.cs b/src/UniTask.NetCore/Linq/OrderByDescending.cs deleted file mode 100644 index 309a0f2..0000000 --- a/src/UniTask.NetCore/Linq/OrderByDescending.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class OrderByDescending - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/ThenBy.cs b/src/UniTask.NetCore/Linq/ThenBy.cs deleted file mode 100644 index 71dfe81..0000000 --- a/src/UniTask.NetCore/Linq/ThenBy.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class ThenBy - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/ThenByDescending.cs b/src/UniTask.NetCore/Linq/ThenByDescending.cs deleted file mode 100644 index aadc421..0000000 --- a/src/UniTask.NetCore/Linq/ThenByDescending.cs +++ /dev/null @@ -1,775 +0,0 @@ -namespace Cysharp.Threading.Tasks.Linq -{ - internal sealed class ThenByDescending - { - } - - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/UniTask.NetCore/Linq/ToLookup.cs b/src/UniTask.NetCore/Linq/ToLookup.cs index c93944b..9cccec0 100644 --- a/src/UniTask.NetCore/Linq/ToLookup.cs +++ b/src/UniTask.NetCore/Linq/ToLookup.cs @@ -544,6 +544,11 @@ namespace Cysharp.Threading.Tasks.Linq { return this.ToUniTaskAsyncEnumerable().GetAsyncEnumerator(cancellationToken); } + + public override string ToString() + { + return "Key: " + Key + ", Count: " + elements.Count; + } } } } \ No newline at end of file diff --git a/src/UniTask.NetCore/Linq/_FileMaker.cs b/src/UniTask.NetCore/Linq/_FileMaker.cs index df91ad8..bd80f4d 100644 --- a/src/UniTask.NetCore/Linq/_FileMaker.cs +++ b/src/UniTask.NetCore/Linq/_FileMaker.cs @@ -31,35 +31,6 @@ namespace ___Dummy - public static IUniTaskAsyncEnumerable GroupJoin(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) - { - throw new NotImplementedException(); - } - - public static IUniTaskAsyncEnumerable GroupJoin(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer) - { - throw new NotImplementedException(); - } - - public static IUniTaskAsyncEnumerable GroupJoinAwait(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> resultSelector) - { - throw new NotImplementedException(); - } - - public static IUniTaskAsyncEnumerable GroupJoinAwait(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, UniTask> resultSelector, IEqualityComparer comparer) - { - throw new NotImplementedException(); - } - - public static IUniTaskAsyncEnumerable GroupJoinAwaitWithCancellation(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector) - { - throw new NotImplementedException(); - } - - public static IUniTaskAsyncEnumerable GroupJoinAwaitWithCancellation(this IUniTaskAsyncEnumerable outer, IUniTaskAsyncEnumerable inner, Func> outerKeySelector, Func> innerKeySelector, Func, CancellationToken, UniTask> resultSelector, IEqualityComparer comparer) - { - throw new NotImplementedException(); - } @@ -125,13 +96,6 @@ namespace ___Dummy throw new NotImplementedException(); } - - - - - - - public static IOrderedAsyncEnumerable ThenBy(this IOrderedAsyncEnumerable source, Func keySelector) { throw new NotImplementedException(); diff --git a/src/UniTask.NetCoreTests/Linq/Joins.cs b/src/UniTask.NetCoreTests/Linq/Joins.cs index bc276e0..48fd120 100644 --- a/src/UniTask.NetCoreTests/Linq/Joins.cs +++ b/src/UniTask.NetCoreTests/Linq/Joins.cs @@ -185,5 +185,69 @@ namespace NetCoreTests.Linq await Assert.ThrowsAsync(async () => await zs); } } + + + + [Fact] + public async Task GroupJoin() + { + var outer = new[] { 1, 2, 4, 5, 8, 10, 14, 4, 8, 1, 2, 10 }; + var inner = new[] { 1, 2, 1, 2, 1, 14, 2 }; + + { + var xs = await outer.ToUniTaskAsyncEnumerable().GroupJoin(inner.ToUniTaskAsyncEnumerable(), x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArrayAsync(); + var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray(); + + xs.Length.Should().Be(ys.Length); + xs.Should().BeEquivalentTo(ys); + } + { + var xs = await outer.ToUniTaskAsyncEnumerable().GroupJoinAwait(inner.ToUniTaskAsyncEnumerable(), x => RandomRun(x), x => RandomRun(x), (x, y) => RandomRun((x, string.Join(", ", y)))).ToArrayAsync(); + var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray(); + + xs.Length.Should().Be(ys.Length); + xs.Should().BeEquivalentTo(ys); + } + { + var xs = await outer.ToUniTaskAsyncEnumerable().GroupJoinAwaitWithCancellation(inner.ToUniTaskAsyncEnumerable(), (x, _) => RandomRun(x), (x, _) => RandomRun(x), (x, y, _) => RandomRun((x, string.Join(", ", y)))).ToArrayAsync(); + var ys = outer.GroupJoin(inner, x => x, x => x, (x, y) => (x, string.Join(", ", y))).ToArray(); + + xs.Length.Should().Be(ys.Length); + xs.Should().BeEquivalentTo(ys); + } + } + + + [Fact] + public async Task GroupJoinThrow() + { + + var outer = new[] { 1, 2, 4, 5, 8, 10, 14, 4, 8, 1, 2, 10 }.ToUniTaskAsyncEnumerable(); + var inner = new[] { 1, 2, 1, 2, 1, 14, 2 }.ToUniTaskAsyncEnumerable(); + + foreach (var item in UniTaskTestException.Throws()) + { + { + var xs = item.GroupJoin(outer, x => x, x => x, (x, y) => x).ToArrayAsync(); + var ys = inner.GroupJoin(item, x => x, x => x, (x, y) => x).ToArrayAsync(); + await Assert.ThrowsAsync(async () => await xs); + await Assert.ThrowsAsync(async () => await ys); + } + { + var xs = item.GroupJoinAwait(outer, x => RandomRun(x), x => RandomRun(x), (x, y) => RandomRun(x)).ToArrayAsync(); + var ys = inner.GroupJoinAwait(item, x => RandomRun(x), x => RandomRun(x), (x, y) => RandomRun(x)).ToArrayAsync(); + await Assert.ThrowsAsync(async () => await xs); + await Assert.ThrowsAsync(async () => await ys); + } + { + var xs = item.GroupJoinAwaitWithCancellation(outer, (x, _) => RandomRun(x), (x, _) => RandomRun(x), (x, y, _) => RandomRun(x)).ToArrayAsync(); + var ys = inner.GroupJoinAwaitWithCancellation(item, (x, _) => RandomRun(x), (x, _) => RandomRun(x), (x, y, _) => RandomRun(x)).ToArrayAsync(); + await Assert.ThrowsAsync(async () => await xs); + await Assert.ThrowsAsync(async () => await ys); + } + } + } + + } }