// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; namespace System.Linq { public static partial class AsyncEnumerableEx { private static IAsyncEnumerator CreateEnumerator(Func, Task> moveNext, Func current, Func dispose) { var self = new AnonymousAsyncIterator( async () => { var tcs = new TaskCompletionSource(); return await moveNext(tcs).ConfigureAwait(false); }, current, dispose ); return self; } private sealed class AnonymousAsyncIterator : AsyncIterator { private readonly Func currentFunc; private readonly Func dispose; private readonly Func> moveNext; public AnonymousAsyncIterator(Func> moveNext, Func currentFunc, Func dispose) { Debug.Assert(moveNext != null); this.moveNext = moveNext; this.currentFunc = currentFunc; this.dispose = dispose; // Explicit call to initialize enumerator mode GetAsyncEnumerator(); } public override AsyncIterator Clone() { throw new NotSupportedException("AnonymousAsyncIterator cannot be cloned. It is only intended for use as an iterator."); } public override async Task DisposeAsync() { if (dispose != null) { await dispose().ConfigureAwait(false); } await base.DisposeAsync().ConfigureAwait(false); } protected override async Task MoveNextCore() { switch (state) { case AsyncIteratorState.Allocated: state = AsyncIteratorState.Iterating; goto case AsyncIteratorState.Iterating; case AsyncIteratorState.Iterating: if (await moveNext().ConfigureAwait(false)) { current = currentFunc(); return true; } await DisposeAsync().ConfigureAwait(false); break; } return false; } } } }