CSharpPatternBasedAwaitAdapter
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace NUnit.Framework.Internal
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal static class CSharpPatternBasedAwaitAdapter
{
[System.Runtime.CompilerServices.Nullable(0)]
private sealed class AwaitShapeInfo
{
private readonly MethodInfo _getAwaiterMethod;
private readonly MethodInfo _isCompletedGetter;
private readonly MethodInfo _onCompletedMethod;
private readonly MethodInfo _getResultMethod;
public Type ResultType => _getResultMethod.ReturnType;
public AwaitShapeInfo(MethodInfo getAwaiterMethod, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod)
{
_getAwaiterMethod = getAwaiterMethod;
_isCompletedGetter = isCompletedGetter;
_onCompletedMethod = onCompletedMethod;
_getResultMethod = getResultMethod;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public static AwaitShapeInfo TryCreate(Type awaitableType)
{
MethodInfo nonGenericPublicInstanceMethod = awaitableType.GetNonGenericPublicInstanceMethod("GetAwaiter", Type.EmptyTypes);
if ((object)nonGenericPublicInstanceMethod == null || nonGenericPublicInstanceMethod.GetGenericArguments().Length != 0)
return null;
Type returnType = nonGenericPublicInstanceMethod.ReturnType;
Type interface = returnType.GetInterface("System.Runtime.CompilerServices.INotifyCompletion");
if ((object)interface == null)
return null;
MethodInfo nonGenericPublicInstanceMethod2 = interface.GetNonGenericPublicInstanceMethod("OnCompleted", new Type[1] {
typeof(Action)
});
if ((object)nonGenericPublicInstanceMethod2 == null)
return null;
PropertyInfo publicInstanceProperty = returnType.GetPublicInstanceProperty("IsCompleted", Type.EmptyTypes);
if ((object)publicInstanceProperty == null || publicInstanceProperty.PropertyType != typeof(bool))
return null;
MethodInfo getMethod = publicInstanceProperty.GetGetMethod();
if ((object)getMethod == null)
return null;
MethodInfo nonGenericPublicInstanceMethod3 = returnType.GetNonGenericPublicInstanceMethod("GetResult", Type.EmptyTypes);
if ((object)nonGenericPublicInstanceMethod3 == null)
return null;
MethodInfo methodInfo = returnType.GetInterface("System.Runtime.CompilerServices.ICriticalNotifyCompletion")?.GetNonGenericPublicInstanceMethod("UnsafeOnCompleted", new Type[1] {
typeof(Action)
});
return new AwaitShapeInfo(nonGenericPublicInstanceMethod, getMethod, methodInfo ?? nonGenericPublicInstanceMethod2, nonGenericPublicInstanceMethod3);
}
public AwaitAdapter CreateAwaitAdapter(object awaitable)
{
return new ReflectionAdapter(_getAwaiterMethod.InvokeWithTransparentExceptions(awaitable), _isCompletedGetter, _onCompletedMethod, _getResultMethod);
}
}
[System.Runtime.CompilerServices.Nullable(0)]
private sealed class ReflectionAdapter : DefaultBlockingAwaitAdapter
{
[System.Runtime.CompilerServices.Nullable(2)]
private readonly object _awaiter;
private readonly Func<bool> _awaiterIsCompleted;
private readonly Action<Action> _awaiterOnCompleted;
private readonly MethodInfo _getResultMethod;
public override bool IsCompleted => _awaiterIsCompleted();
public ReflectionAdapter([System.Runtime.CompilerServices.Nullable(2)] object awaiter, MethodInfo isCompletedGetter, MethodInfo onCompletedMethod, MethodInfo getResultMethod)
{
_awaiter = awaiter;
_awaiterIsCompleted = (Func<bool>)isCompletedGetter.CreateDelegate(typeof(Func<bool>), awaiter);
_awaiterOnCompleted = (Action<Action>)onCompletedMethod.CreateDelegate(typeof(Action<Action>), awaiter);
_getResultMethod = getResultMethod;
}
public override void OnCompleted(Action action)
{
_awaiterOnCompleted(action);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override object GetResult()
{
return _getResultMethod.InvokeWithTransparentExceptions(_awaiter);
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
1,
1,
2
})]
private static readonly ConcurrentDictionary<Type, AwaitShapeInfo> ShapeInfoByType = new ConcurrentDictionary<Type, AwaitShapeInfo>();
[System.Runtime.CompilerServices.NullableContext(2)]
public static AwaitAdapter TryCreate(object awaitable)
{
if (awaitable == null)
return null;
return GetShapeInfo(awaitable.GetType())?.CreateAwaitAdapter(awaitable);
}
public static bool IsAwaitable(Type awaitableType)
{
return GetShapeInfo(awaitableType) != null;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public static Type GetResultType(Type awaitableType)
{
return GetShapeInfo(awaitableType)?.ResultType;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static AwaitShapeInfo GetShapeInfo(Type type)
{
return ShapeInfoByType.GetOrAdd(type, AwaitShapeInfo.TryCreate);
}
}
}