#if !BCL_HAS_CONFIGUREAWAIT
// 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.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
/// Represents a builder for asynchronous iterators.
[StructLayout(LayoutKind.Auto)]
public struct AsyncIteratorMethodBuilder
{
// AsyncIteratorMethodBuilder is used by the language compiler as part of generating
// async iterators. For now, the implementation just wraps AsyncTaskMethodBuilder, as
// most of the logic is shared. However, in the future this could be changed and
// optimized. For example, we do need to allocate an object (once) to flow state like
// ExecutionContext, which AsyncTaskMethodBuilder handles, but it handles it by
// allocating a Task-derived object. We could optimize this further by removing
// the Task from the hierarchy, but in doing so we'd also lose a variety of optimizations
// related to it, so we'd need to replicate all of those optimizations (e.g. storing
// that box object directly into a Task's continuation field).
#pragma warning disable IDE0044 // Add readonly modifier
private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
#pragma warning restore IDE0044 // Add readonly modifier
/// Creates an instance of the struct.
/// The initialized instance.
public static AsyncIteratorMethodBuilder Create() =>
#if PROJECTN
// ProjectN's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
// work, so we need to delegate to it.
new AsyncIteratorMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
#else
// _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
// that Create() is a nop, so we can just return the default here.
default;
#endif
/// Invokes on the state machine while guarding the .
/// The type of the state machine.
/// The state machine instance, passed by reference.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MoveNext(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
#if CORERT || !BCL_HAS_CONFIGUREAWAIT
_methodBuilder.Start(ref stateMachine);
#else
AsyncMethodBuilderCore.Start(ref stateMachine);
#endif
/// Schedules the state machine to proceed to the next action when the specified awaiter completes.
/// The type of the awaiter.
/// The type of the state machine.
/// The awaiter.
/// The state machine.
public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
/// Schedules the state machine to proceed to the next action when the specified awaiter completes.
/// The type of the awaiter.
/// The type of the state machine.
/// The awaiter.
/// The state machine.
public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine =>
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
/// Marks iteration as being completed, whether successfully or otherwise.
public void Complete() => _methodBuilder.SetResult();
/// Gets an object that may be used to uniquely identify this builder to the debugger.
internal object ObjectIdForDebugger => typeof(AsyncTaskMethodBuilder)
.GetProperty("ObjectIdForDebugger", BindingFlags.Instance | BindingFlags.NonPublic)
.GetMethod.Invoke(_methodBuilder, null);
}
}
#else
using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(AsyncIteratorMethodBuilder))]
#endif