// 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
}