|  | @@ -21,47 +21,7 @@ namespace System.Linq
 | 
	
		
			
				|  |  |              if (comparer == null)
 | 
	
		
			
				|  |  |                  throw new ArgumentNullException(nameof(comparer));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            return CreateEnumerable(
 | 
	
		
			
				|  |  | -                () =>
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    var e = first.GetEnumerator();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var cts = new CancellationTokenDisposable();
 | 
	
		
			
				|  |  | -                    var d = Disposable.Create(cts, e);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var mapTask = default(Task<Dictionary<TSource, TSource>>);
 | 
	
		
			
				|  |  | -                    var getMapTask = new Func<CancellationToken, Task<Dictionary<TSource, TSource>>>(
 | 
	
		
			
				|  |  | -                        ct =>
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            if (mapTask == null)
 | 
	
		
			
				|  |  | -                                mapTask = second.ToDictionary(x => x, comparer, ct);
 | 
	
		
			
				|  |  | -                            return mapTask;
 | 
	
		
			
				|  |  | -                        });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var f = default(Func<CancellationToken, Task<bool>>);
 | 
	
		
			
				|  |  | -                    f = async ct =>
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            if (await e.MoveNext(ct)
 | 
	
		
			
				|  |  | -                                       .Zip(getMapTask(ct), (b, _) => b)
 | 
	
		
			
				|  |  | -                                       .ConfigureAwait(false))
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                // Note: Result here is safe because the task
 | 
	
		
			
				|  |  | -                                // was completed in the Zip() call above
 | 
	
		
			
				|  |  | -                                if (mapTask.Result.ContainsKey(e.Current))
 | 
	
		
			
				|  |  | -                                    return true;
 | 
	
		
			
				|  |  | -                                return await f(ct)
 | 
	
		
			
				|  |  | -                                           .ConfigureAwait(false);
 | 
	
		
			
				|  |  | -                            }
 | 
	
		
			
				|  |  | -                            return false;
 | 
	
		
			
				|  |  | -                        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    return CreateEnumerator(
 | 
	
		
			
				|  |  | -                        f,
 | 
	
		
			
				|  |  | -                        () => e.Current,
 | 
	
		
			
				|  |  | -                        d.Dispose,
 | 
	
		
			
				|  |  | -                        e
 | 
	
		
			
				|  |  | -                    );
 | 
	
		
			
				|  |  | -                });
 | 
	
		
			
				|  |  | +            return new IntersectAsyncIterator<TSource>(first, second, comparer);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -74,5 +34,103 @@ namespace System.Linq
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return first.Intersect(second, EqualityComparer<TSource>.Default);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private sealed class IntersectAsyncIterator<TSource> : AsyncIterator<TSource>
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            private readonly IEqualityComparer<TSource> comparer;
 | 
	
		
			
				|  |  | +            private readonly IAsyncEnumerable<TSource> first;
 | 
	
		
			
				|  |  | +            private readonly IAsyncEnumerable<TSource> second;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            private Task fillSetTask;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            private IAsyncEnumerator<TSource> firstEnumerator;
 | 
	
		
			
				|  |  | +            private Set<TSource> set;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            private bool setFilled;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            public IntersectAsyncIterator(IAsyncEnumerable<TSource> first, IAsyncEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                this.first = first;
 | 
	
		
			
				|  |  | +                this.second = second;
 | 
	
		
			
				|  |  | +                this.comparer = comparer;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            public override AsyncIterator<TSource> Clone()
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                return new IntersectAsyncIterator<TSource>(first, second, comparer);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            public override void Dispose()
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (firstEnumerator != null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    firstEnumerator.Dispose();
 | 
	
		
			
				|  |  | +                    firstEnumerator = null;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                set = null;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                base.Dispose();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            protected override async Task<bool> MoveNextCore(CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                switch (state)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    case AsyncIteratorState.Allocated:
 | 
	
		
			
				|  |  | +                        firstEnumerator = first.GetEnumerator();
 | 
	
		
			
				|  |  | +                        set = new Set<TSource>(comparer);
 | 
	
		
			
				|  |  | +                        setFilled = false;
 | 
	
		
			
				|  |  | +                        fillSetTask = FillSet(cancellationToken);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        state = AsyncIteratorState.Iterating;
 | 
	
		
			
				|  |  | +                        goto case AsyncIteratorState.Iterating;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    case AsyncIteratorState.Iterating:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        bool moveNext;
 | 
	
		
			
				|  |  | +                        if (!setFilled)
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            // This is here so we don't need to call Task.WhenAll each time after the set is filled
 | 
	
		
			
				|  |  | +                            var moveNextTask = firstEnumerator.MoveNext(cancellationToken);
 | 
	
		
			
				|  |  | +                            await Task.WhenAll(moveNextTask, fillSetTask)
 | 
	
		
			
				|  |  | +                                      .ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                            setFilled = true;
 | 
	
		
			
				|  |  | +                            moveNext = moveNextTask.Result;
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        else
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            moveNext = await firstEnumerator.MoveNext(cancellationToken)
 | 
	
		
			
				|  |  | +                                                            .ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        if (moveNext)
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            var item = firstEnumerator.Current;
 | 
	
		
			
				|  |  | +                            if (set.Remove(item))
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                current = item;
 | 
	
		
			
				|  |  | +                                return true;
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                            goto case AsyncIteratorState.Iterating; // loop
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        Dispose();
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                return false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            private async Task FillSet(CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var array = await second.ToArray(cancellationToken)
 | 
	
		
			
				|  |  | +                                        .ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                for (var i = 0; i < array.Length; i++)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    set.Add(array[i]);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |