// 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.Threading.Tasks; using System.Threading.Tasks.Sources; #if !netstandard using Internal.Runtime.CompilerServices; #endif namespace System.Runtime.CompilerServices { /// Provides an awaiter for a . public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion #if CORECLR , IStateMachineBoxAwareAwaiter #endif { /// Shim used to invoke an passed as the state argument to a . internal static readonly Action s_invokeActionDelegate = state => { if (!(state is Action action)) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); return; } action(); }; /// The value being awaited. private readonly ValueTask _value; /// Initializes the awaiter. /// The value to be awaited. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTaskAwaiter(ValueTask value) => _value = value; /// Gets whether the has completed. public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _value.IsCompleted; } /// Gets the result of the ValueTask. [StackTraceHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); /// Schedules the continuation action for this ValueTask. public void OnCompleted(Action continuation) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { t.GetAwaiter().OnCompleted(continuation); } else if (obj != null) { Unsafe.As(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); } } /// Schedules the continuation action for this ValueTask. public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { t.GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { Unsafe.As(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); } } #if CORECLR void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext: true); } else if (obj != null) { Unsafe.As(obj).OnCompleted(s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); } } /// Shim used to invoke of the supplied . internal static readonly Action s_invokeAsyncStateMachineBox = state => { if (!(state is IAsyncStateMachineBox box)) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); return; } box.MoveNext(); }; #endif } /// Provides an awaiter for a . public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion #if CORECLR , IStateMachineBoxAwareAwaiter #endif { /// The value being awaited. private readonly ValueTask _value; /// Initializes the awaiter. /// The value to be awaited. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTaskAwaiter(ValueTask value) => _value = value; /// Gets whether the has completed. public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _value.IsCompleted; } /// Gets the result of the ValueTask. [StackTraceHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public TResult GetResult() => _value.Result; /// Schedules the continuation action for this ValueTask. public void OnCompleted(Action continuation) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { t.GetAwaiter().OnCompleted(continuation); } else if (obj != null) { Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); } } /// Schedules the continuation action for this ValueTask. public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { t.GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); } } #if CORECLR void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) { object obj = _value._obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj is Task t) { TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext: true); } else if (obj != null) { Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); } } #endif } #if CORECLR /// Internal interface used to enable optimizations from .> internal interface IStateMachineBoxAwareAwaiter { /// Invoked to set of the as the awaiter's continuation. /// The box object. void AwaitUnsafeOnCompleted(IAsyncStateMachineBox box); } #endif }