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 Distinct(this IUniTaskAsyncEnumerable source) { return Distinct(source, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable Distinct(this IUniTaskAsyncEnumerable source, IEqualityComparer comparer) { Error.ThrowArgumentNullException(source, nameof(source)); Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new Distinct(source, comparer); } public static IUniTaskAsyncEnumerable Distinct(this IUniTaskAsyncEnumerable source, Func keySelector) { return Distinct(source, keySelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable Distinct(this IUniTaskAsyncEnumerable source, Func keySelector, IEqualityComparer comparer) { Error.ThrowArgumentNullException(source, nameof(source)); Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new Distinct(source, keySelector, comparer); } public static IUniTaskAsyncEnumerable DistinctAwait(this IUniTaskAsyncEnumerable source, Func> keySelector) { return DistinctAwait(source, keySelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable DistinctAwait(this IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { Error.ThrowArgumentNullException(source, nameof(source)); Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new DistinctAwait(source, keySelector, comparer); } public static IUniTaskAsyncEnumerable DistinctAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector) { return DistinctAwaitWithCancellation(source, keySelector, EqualityComparer.Default); } public static IUniTaskAsyncEnumerable DistinctAwaitWithCancellation(this IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { Error.ThrowArgumentNullException(source, nameof(source)); Error.ThrowArgumentNullException(keySelector, nameof(keySelector)); Error.ThrowArgumentNullException(comparer, nameof(comparer)); return new DistinctAwaitWithCancellation(source, keySelector, comparer); } } internal sealed class Distinct : IUniTaskAsyncEnumerable { readonly IUniTaskAsyncEnumerable source; readonly IEqualityComparer comparer; public Distinct(IUniTaskAsyncEnumerable source, IEqualityComparer comparer) { this.source = source; this.comparer = comparer; } public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return new _Distinct(source, comparer, cancellationToken); } class _Distinct : AsyncEnumeratorBase { readonly HashSet set; public _Distinct(IUniTaskAsyncEnumerable source, IEqualityComparer comparer, CancellationToken cancellationToken) : base(source, cancellationToken) { this.set = new HashSet(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 : IUniTaskAsyncEnumerable { readonly IUniTaskAsyncEnumerable source; readonly Func keySelector; readonly IEqualityComparer comparer; public Distinct(IUniTaskAsyncEnumerable source, Func keySelector, IEqualityComparer comparer) { this.source = source; this.keySelector = keySelector; this.comparer = comparer; } public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return new _Distinct(source, keySelector, comparer, cancellationToken); } class _Distinct : AsyncEnumeratorBase { readonly HashSet set; readonly Func keySelector; public _Distinct(IUniTaskAsyncEnumerable source, Func keySelector, IEqualityComparer comparer, CancellationToken cancellationToken) : base(source, cancellationToken) { this.set = new HashSet(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 : IUniTaskAsyncEnumerable { readonly IUniTaskAsyncEnumerable source; readonly Func> keySelector; readonly IEqualityComparer comparer; public DistinctAwait(IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { this.source = source; this.keySelector = keySelector; this.comparer = comparer; } public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return new _DistinctAwait(source, keySelector, comparer, cancellationToken); } class _DistinctAwait : AsyncEnumeratorAwaitSelectorBase { readonly HashSet set; readonly Func> keySelector; public _DistinctAwait(IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer, CancellationToken cancellationToken) : base(source, cancellationToken) { this.set = new HashSet(comparer); this.keySelector = keySelector; } protected override UniTask 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 : IUniTaskAsyncEnumerable { readonly IUniTaskAsyncEnumerable source; readonly Func> keySelector; readonly IEqualityComparer comparer; public DistinctAwaitWithCancellation(IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer) { this.source = source; this.keySelector = keySelector; this.comparer = comparer; } public IUniTaskAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return new _DistinctAwaitWithCancellation(source, keySelector, comparer, cancellationToken); } class _DistinctAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase { readonly HashSet set; readonly Func> keySelector; public _DistinctAwaitWithCancellation(IUniTaskAsyncEnumerable source, Func> keySelector, IEqualityComparer comparer, CancellationToken cancellationToken) : base(source, cancellationToken) { this.set = new HashSet(comparer); this.keySelector = keySelector; } protected override UniTask 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; } } } } }