// 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;
}
}
}
}