// 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.Tasks;
namespace System.Linq
{
    public static partial class AsyncEnumerable
    {
        // REVIEW: This type of blocking is an anti-pattern. We may want to move it to System.Interactive.Async
        //         and remove it from System.Linq.Async API surface.
        /// 
        /// Converts an async-enumerable sequence to an enumerable sequence.
        /// 
        /// The type of the elements in the source sequence.
        /// An async-enumerable sequence to convert to an enumerable sequence.
        /// The enumerable sequence containing the elements in the async-enumerable sequence.
        ///  is null.
        public static IEnumerable ToEnumerable(this IAsyncEnumerable source)
        {
            if (source == null)
                throw Error.ArgumentNull(nameof(source));
            return Core(source);
            static IEnumerable Core(IAsyncEnumerable source)
            {
                var e = source.GetAsyncEnumerator(default);
                try
                {
                    while (true)
                    {
                        if (!Wait(e.MoveNextAsync()))
                            break;
                        yield return e.Current;
                    }
                }
                finally
                {
                    Wait(e.DisposeAsync());
                }
            }
        }
        // NB: ValueTask and ValueTask do not have to support blocking on a call to GetResult when backed by
        //     an IValueTaskSource or IValueTaskSource implementation. Convert to a Task or Task to do so
        //     in case the task hasn't completed yet.
        private static void Wait(ValueTask task)
        {
            var awaiter = task.GetAwaiter();
            if (!awaiter.IsCompleted)
            {
                task.AsTask().GetAwaiter().GetResult();
                return;
            }
            awaiter.GetResult();
        }
        private static T Wait(ValueTask task)
        {
            var awaiter = task.GetAwaiter();
            if (!awaiter.IsCompleted)
            {
                return task.AsTask().GetAwaiter().GetResult();
            }
            return awaiter.GetResult();
        }
    }
}