// 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;
namespace System.Linq
{
    public static partial class AsyncEnumerableEx
    {
        // REVIEW: Add async variant?
        /// 
        /// Generates an async-enumerable sequence by running a state-driven loop producing the sequence's elements.
        /// 
        /// The type of the state used in the generator loop.
        /// The type of the elements in the produced sequence.
        /// Initial state.
        /// Condition to terminate generation (upon returning false).
        /// Iteration step function.
        /// Selector function for results produced in the sequence.
        /// The generated sequence.
        ///  or  or  is null.
        public static IAsyncEnumerable Generate(TState initialState, Func condition, Func iterate, Func resultSelector)
        {
            if (condition == null)
                throw Error.ArgumentNull(nameof(condition));
            if (iterate == null)
                throw Error.ArgumentNull(nameof(iterate));
            if (resultSelector == null)
                throw Error.ArgumentNull(nameof(resultSelector));
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
            return Core(initialState, condition, iterate, resultSelector);
            static async IAsyncEnumerable Core(TState initialState, Func condition, Func iterate, Func resultSelector, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
            {
                for (var state = initialState; condition(state); state = iterate(state))
                {
                    // REVIEW: Check for cancellation?
                    yield return resultSelector(state);
                }
            }
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        }
    }
}