// 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.Linq; using System.Threading; using System.Threading.Tasks; namespace System.Collections.Generic { /// /// Provides a set of extension methods for . /// public static partial class AsyncEnumerator { // // REVIEW: Create methods may not belong in System.Linq.Async. Async iterators can be // used to implement these interfaces. Move to System.Interactive.Async? // /// /// Creates a new enumerator using the specified delegates implementing the members of . /// /// The type of the elements returned by the enumerator. /// The delegate implementing the method. /// The delegate implementing the property getter. /// The delegate implementing the method. /// A new enumerator instance. public static IAsyncEnumerator Create(Func> moveNextAsync, Func getCurrent, Func disposeAsync) { if (moveNextAsync == null) throw Error.ArgumentNull(nameof(moveNextAsync)); // // NB: Callers can pass null for the second two parameters, which can be useful to // implement enumerators that throw or yield no results. // return new AnonymousAsyncIterator(moveNextAsync, getCurrent, disposeAsync); } /// /// Advances the enumerator to the next element in the sequence, returning the result asynchronously. /// /// The type of the elements returned by the enumerator. /// The enumerator to advance. /// Cancellation token that can be used to cancel the operation. /// /// Task containing the result of the operation: true if the enumerator was successfully advanced /// to the next element; false if the enumerator has passed the end of the sequence. /// public static ValueTask MoveNextAsync(this IAsyncEnumerator source, CancellationToken cancellationToken) { if (source == null) throw Error.ArgumentNull(nameof(source)); cancellationToken.ThrowIfCancellationRequested(); return source.MoveNextAsync(); } private sealed class AnonymousAsyncIterator : AsyncIterator { private readonly Func _currentFunc; private readonly Func> _moveNext; private Func? _dispose; public AnonymousAsyncIterator(Func> moveNext, Func currentFunc, Func dispose) { _moveNext = moveNext; _currentFunc = currentFunc; _dispose = dispose; // Explicit call to initialize enumerator mode GetAsyncEnumerator(default); } public override AsyncIteratorBase Clone() { throw new NotSupportedException("AnonymousAsyncIterator cannot be cloned. It is only intended for use as an iterator."); } public override async ValueTask DisposeAsync() { var dispose = Interlocked.Exchange(ref _dispose, null); if (dispose != null) { await dispose().ConfigureAwait(false); } await base.DisposeAsync().ConfigureAwait(false); } protected override async ValueTask 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; } } } }