// 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; using System.Threading.Tasks; namespace System.Linq { public static partial class AsyncEnumerable { public static IAsyncEnumerable CreateEnumerable(Func> getEnumerator) { if (getEnumerator == null) throw Error.ArgumentNull(nameof(getEnumerator)); return new AnonymousAsyncEnumerable(getEnumerator); } public static WithCancellationAsyncEnumerable WithCancellation(this IAsyncEnumerable source, CancellationToken cancellationToken) { if (source == null) throw Error.ArgumentNull(nameof(source)); return new WithCancellationAsyncEnumerable(source, cancellationToken); } private sealed class AnonymousAsyncEnumerable : IAsyncEnumerable { private readonly Func> _getEnumerator; public AnonymousAsyncEnumerable(Func> getEnumerator) { Debug.Assert(getEnumerator != null); _getEnumerator = getEnumerator; } public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken) => _getEnumerator(cancellationToken); } // REVIEW: Explicit implementation of the interfaces allows for composition with other "modifier operators" such as ConfigureAwait. // We expect that the "await foreach" statement will bind to the public struct methods, thus avoiding boxing. public readonly struct WithCancellationAsyncEnumerable : IAsyncEnumerable { private readonly IAsyncEnumerable _source; private readonly CancellationToken _cancellationToken; public WithCancellationAsyncEnumerable(IAsyncEnumerable source, CancellationToken cancellationToken) { _source = source; _cancellationToken = cancellationToken; } // REVIEW: Should we simply ignore the second cancellation token or should we link the two? public WithCancellationAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken) => new WithCancellationAsyncEnumerator(_source.GetAsyncEnumerator(_cancellationToken)); IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken) => GetAsyncEnumerator(cancellationToken); public readonly struct WithCancellationAsyncEnumerator : IAsyncEnumerator { private readonly IAsyncEnumerator _enumerator; public WithCancellationAsyncEnumerator(IAsyncEnumerator enumerator) { _enumerator = enumerator; } public T Current => _enumerator.Current; public ValueTask DisposeAsync() => _enumerator.DisposeAsync(); public ValueTask MoveNextAsync() => _enumerator.MoveNextAsync(); } } } }