44
55namespace NetCord . Services . Helpers ;
66
7- internal class InvocationHelper
7+ file static class InvocationHelper < TContext >
88{
9+ internal static readonly MethodInfo _baseModuleSetContextMethod = typeof ( IBaseModule < TContext > ) . GetMethod ( nameof ( IBaseModule < > . SetContext ) , BindingFlags . Instance | BindingFlags . NonPublic ) ! ;
10+ }
11+
12+ internal static class InvocationHelper
13+ {
14+ private static readonly MethodInfo _valueTaskAsTaskMethod = typeof ( ValueTask ) . GetMethod ( nameof ( ValueTask . AsTask ) , BindingFlags . Instance | BindingFlags . Public ) ! ;
15+ private static readonly MethodInfo _valueTaskOfTAsTaskMethodUnbound = typeof ( ValueTask < > ) . GetMethod ( nameof ( ValueTask < > . AsTask ) , BindingFlags . Instance | BindingFlags . Public ) ! ;
16+
917 public static Func < object ? [ ] ? , TContext , IServiceProvider ? , ValueTask > CreateModuleDelegate < TContext > ( MethodInfo method , [ DynamicallyAccessedMembers ( DynamicallyAccessedMemberTypes . PublicConstructors ) ] Type declaringType , IEnumerable < Type > parameterTypes , IResultResolverProvider < TContext > resultResolverProvider , IServiceResolverProvider serviceResolverProvider )
1018 {
1119 var parameters = Expression . Parameter ( typeof ( object ? [ ] ) ) ;
@@ -19,16 +27,15 @@ internal class InvocationHelper
1927 var module = Expression . Variable ( declaringType ) ;
2028 instance = Expression . Block ( [ module ] ,
2129 Expression . Assign ( module , TypeHelper . GetCreateInstanceExpression ( declaringType , serviceProvider , serviceResolverProvider ) ) ,
22- Expression . Call ( module , typeof ( IBaseModule < TContext > ) . GetMethod ( nameof ( IBaseModule < > . SetContext ) , BindingFlags . Instance | BindingFlags . NonPublic ) ! , context ) ,
30+ Expression . Call ( module , InvocationHelper < TContext > . _baseModuleSetContextMethod , context ) ,
2331 module ) ;
2432 }
2533
2634 var call = Expression . Call ( instance ,
2735 method ,
2836 parameterTypes . Select ( ( p , i ) => Expression . Convert ( Expression . ArrayIndex ( parameters , Expression . Constant ( i , typeof ( int ) ) ) , p ) ) ) ;
2937
30- var resolver = GetResolver ( method , resultResolverProvider ) ;
31- var invokeResolver = GetInvokeResolverExpression ( method , context , call , resolver ) ;
38+ var invokeResolver = GetInvokeResolverExpression ( method , context , call , resultResolverProvider ) ;
3239
3340 var lambda = Expression . Lambda < Func < object ? [ ] ? , TContext , IServiceProvider ? , ValueTask > > ( invokeResolver , parameters , context , serviceProvider ) ;
3441 return lambda . Compile ( ) ;
@@ -49,36 +56,76 @@ internal class InvocationHelper
4956
5057 var method = handler . Method ;
5158
52- var resolver = GetResolver ( method , resultResolverProvider ) ;
53- var invokeResolver = GetInvokeResolverExpression ( method , context , invoke , resolver ) ;
59+ var invokeResolver = GetInvokeResolverExpression ( method , context , invoke , resultResolverProvider ) ;
5460
5561 var lambda = Expression . Lambda < Func < object ? [ ] ? , TContext , IServiceProvider ? , ValueTask > > ( invokeResolver , parameters , context , serviceProvider ) ;
5662 return lambda . Compile ( ) ;
5763 }
5864
59- private static Func < object ? , TContext , ValueTask > GetResolver < TContext > ( MethodInfo method , IResultResolverProvider < TContext > resultResolverProvider )
65+ [ DoesNotReturn ]
66+ private static void ThrowResolverTypeNotSupportedException < TContext > ( MethodInfo method , Type returnType , IResultResolverProvider < TContext > resultResolverProvider )
6067 {
61- var type = method . ReturnType ;
62- if ( resultResolverProvider . TryGetResolver ( type , out var resolver ) )
63- return resolver ;
68+ throw new InvalidDefinitionException ( $ "The return type '{ returnType } ' is not supported by '{ resultResolverProvider . GetType ( ) } '.", method ) ;
69+ }
6470
65- throw new InvalidDefinitionException ( $ "The return type '{ type } ' is not supported by '{ resultResolverProvider . GetType ( ) } '.", method ) ;
71+ [ DoesNotReturn ]
72+ private static void ThrowResolverBothTypesNotSupportedException < TContext > ( MethodInfo method , Type returnType1 , Type returnType2 , IResultResolverProvider < TContext > resultResolverProvider )
73+ {
74+ throw new InvalidDefinitionException ( $ "The return types '{ returnType1 } ' and '{ returnType2 } ' are not supported by '{ resultResolverProvider . GetType ( ) } '.", method ) ;
6675 }
6776
68- private static Expression GetInvokeResolverExpression < TContext > ( MethodInfo method , ParameterExpression context , Expression call , Func < object ? , TContext , ValueTask > resolver )
77+ private static Expression GetInvokeResolverExpression < TContext > ( MethodInfo method , ParameterExpression context , Expression call , IResultResolverProvider < TContext > resultResolverProvider )
6978 {
70- if ( method . ReturnType == typeof ( void ) )
79+ var returnType = method . ReturnType ;
80+
81+ if ( resultResolverProvider . TryGetResolver ( returnType , out var resolver ) )
7182 {
72- return Expression . Block ( call ,
73- Expression . Invoke ( Expression . Constant ( resolver ) ,
74- Expression . Constant ( null , typeof ( object ) ) ,
75- context ) ) ;
83+ if ( returnType == typeof ( void ) )
84+ return Expression . Block ( call ,
85+ Expression . Invoke ( Expression . Constant ( resolver , typeof ( Func < object ? , TContext , ValueTask > ) ) ,
86+ Expression . Constant ( null , typeof ( object ) ) ,
87+ context ) ) ;
88+
89+ return CreateResultResolverCallExpression ( context , call , resolver ) ;
7690 }
77- else
91+
92+ return GetAlternativeInvokeResolverExpression ( method , returnType , context , call , resultResolverProvider ) ;
93+ }
94+
95+ private static InvocationExpression GetAlternativeInvokeResolverExpression < TContext > ( MethodInfo method , Type returnType , ParameterExpression context , Expression call , IResultResolverProvider < TContext > resultResolverProvider )
96+ {
97+ Func < object ? , TContext , ValueTask > ? resolver = null ;
98+
99+ if ( returnType == typeof ( ValueTask ) )
78100 {
79- return Expression . Invoke ( Expression . Constant ( resolver ) ,
80- Expression . Convert ( call , typeof ( object ) ) ,
81- context ) ;
101+ var alternativeReturnType = typeof ( Task ) ;
102+
103+ if ( ! resultResolverProvider . TryGetResolver ( alternativeReturnType , out resolver ) )
104+ ThrowResolverBothTypesNotSupportedException ( method , returnType , alternativeReturnType , resultResolverProvider ) ;
105+
106+ call = Expression . Call ( call , _valueTaskAsTaskMethod ) ;
82107 }
108+ else if ( returnType . IsGenericType && returnType . GetGenericTypeDefinition ( ) == typeof ( ValueTask < > ) )
109+ {
110+ var asTaskMethod = ( MethodInfo ) returnType . GetMemberWithSameMetadataDefinitionAs ( _valueTaskOfTAsTaskMethodUnbound ) ;
111+
112+ var alternativeReturnType = asTaskMethod . ReturnType ;
113+
114+ if ( ! resultResolverProvider . TryGetResolver ( alternativeReturnType , out resolver ) )
115+ ThrowResolverBothTypesNotSupportedException ( method , returnType , alternativeReturnType , resultResolverProvider ) ;
116+
117+ call = Expression . Call ( call , asTaskMethod ) ;
118+ }
119+ else
120+ ThrowResolverTypeNotSupportedException ( method , returnType , resultResolverProvider ) ;
121+
122+ return CreateResultResolverCallExpression ( context , call , resolver ) ;
123+ }
124+
125+ private static InvocationExpression CreateResultResolverCallExpression < TContext > ( ParameterExpression context , Expression call , Func < object ? , TContext , ValueTask > resolver )
126+ {
127+ return Expression . Invoke ( Expression . Constant ( resolver , typeof ( Func < object ? , TContext , ValueTask > ) ) ,
128+ Expression . Convert ( call , typeof ( object ) ) ,
129+ context ) ;
83130 }
84131}
0 commit comments