#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