// 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; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace System.Linq { public static partial class AsyncEnumerable { public static IAsyncEnumerable Create(Func> getEnumerator) { return new AnonymousAsyncEnumerable(getEnumerator); } private class AnonymousAsyncEnumerable : IAsyncEnumerable { private Func> getEnumerator; public AnonymousAsyncEnumerable(Func> getEnumerator) { this.getEnumerator = getEnumerator; } public IAsyncEnumerator GetEnumerator() { return getEnumerator(); } } private static IAsyncEnumerator Create(Func> moveNext, Func current, Action dispose, IDisposable enumerator) { return Create(async ct => { using (ct.Register(dispose)) { try { var result = await moveNext(ct).ConfigureAwait(false); if (!result) { enumerator?.Dispose(); } return result; } catch { enumerator?.Dispose(); throw; } } }, current, dispose); } public static IAsyncEnumerator Create(Func> moveNext, Func current, Action dispose) { return new AnonymousAsyncEnumerator(moveNext, current, dispose); } private static IAsyncEnumerator Create(Func, Task> moveNext, Func current, Action dispose) { var self = default(IAsyncEnumerator); self = new AnonymousAsyncEnumerator( async ct => { var tcs = new TaskCompletionSource(); var stop = new Action(() => { self.Dispose(); tcs.TrySetCanceled(); }); using (ct.Register(stop)) { return await moveNext(ct, tcs).ConfigureAwait(false); } }, current, dispose ); return self; } private class AnonymousAsyncEnumerator : IAsyncEnumerator { private readonly Func> _moveNext; private readonly Func _current; private readonly Action _dispose; private bool _disposed; public AnonymousAsyncEnumerator(Func> moveNext, Func current, Action dispose) { _moveNext = moveNext; _current = current; _dispose = dispose; } public Task MoveNext(CancellationToken cancellationToken) { if (_disposed) return TaskExt.False; return _moveNext(cancellationToken); } public T Current { get { return _current(); } } public void Dispose() { if (!_disposed) { _disposed = true; _dispose(); } } } } }