// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT 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 AsyncEnumerableEx { /// /// Returns a non-terminating async-enumerable sequence, which can be used to denote an infinite duration (e.g. when using reactive joins). /// /// The type used for the type parameter of the resulting sequence. /// An async-enumerable sequence whose consumers will never resume after awaiting . public static IAsyncEnumerable Never() => NeverAsyncEnumerable.Instance; private sealed class NeverAsyncEnumerable : IAsyncEnumerable { internal static readonly NeverAsyncEnumerable Instance = new NeverAsyncEnumerable(); public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // NB: [LDM-2018-11-28] Equivalent to async iterator behavior. return new NeverAsyncEnumerator(cancellationToken); } private sealed class NeverAsyncEnumerator : IAsyncEnumerator { private readonly CancellationToken _token; private CancellationTokenRegistration _registration; private bool _once; public NeverAsyncEnumerator(CancellationToken token) => _token = token; public TValue Current => throw new InvalidOperationException(); public ValueTask DisposeAsync() { _registration.Dispose(); return default; } public ValueTask MoveNextAsync() { if (_once) { return new ValueTask(false); } _once = true; var task = new TaskCompletionSource(); _registration = _token.Register(state => ((TaskCompletionSource)state).TrySetCanceled(_token), task); return new ValueTask(task.Task); } } } } }