// 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.Threading; using System.Threading.Tasks; namespace System.Linq { public static partial class AsyncEnumerable { // REVIEW: [LDM-2018-11-28] Should return type be a struct or just the interface type? Should this live in the System.Linq namespace or in System.Collections.Generic? public static WithCancellationTokenAsyncEnumerable WithCancellation(this IAsyncEnumerable source, CancellationToken cancellationToken) { if (source == null) throw Error.ArgumentNull(nameof(source)); return new WithCancellationTokenAsyncEnumerable(source, 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 WithCancellationTokenAsyncEnumerable : IAsyncEnumerable { private readonly IAsyncEnumerable _source; private readonly CancellationToken _cancellationToken; public WithCancellationTokenAsyncEnumerable(IAsyncEnumerable source, CancellationToken cancellationToken) { _source = source; _cancellationToken = cancellationToken; } // REVIEW: Should we simply ignore the second cancellation token or should we link the two? // REVIEW: [LDM-2018-11-28] Should we have eager cancellation here too? 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(); } } } }