-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
396 additions
and
396 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
Kunet.AsyncInterceptor.Tests/CustomTaskLikeReturnValueExample/AsyncAdapterOfMyTask`.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using Castle.DynamicProxy; | ||
|
||
namespace Kunet.AsyncInterceptor.Tests; | ||
|
||
// You must provide this to set AsyncResult from Invocation.ReturnValue | ||
// You must provide this to adapt your custom TaskMethodBuilder to IAsyncTaskBuilder | ||
|
||
internal sealed class AsyncAdapterOfMyTask<T> : AsyncAdapter | ||
{ | ||
private readonly MyTaskMethodBuilder<T> _builder = MyTaskMethodBuilder<T>.Create(); | ||
|
||
public AsyncAdapterOfMyTask(IInvocation invocation) : base(invocation) => Task = _builder.Task; | ||
|
||
protected override async ValueTask SetAsyncResult() => AsyncResult = await (MyTask<T>)Invocation.ReturnValue; | ||
|
||
public override object Task { get; } | ||
|
||
public override void Start<TStateMachine>(ref TStateMachine stateMachine) => _builder.Start(ref stateMachine); | ||
|
||
public override void SetException(Exception ex) => _builder.SetException(ex); | ||
|
||
public override void SetResult(object result) => _builder.SetResult((T)result); | ||
|
||
public override void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) => _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | ||
} |
17 changes: 0 additions & 17 deletions
17
Kunet.AsyncInterceptor.Tests/CustomTaskLikeReturnValueExample/AsyncInvocationOfMyTask`.cs
This file was deleted.
Oops, something went wrong.
24 changes: 0 additions & 24 deletions
24
Kunet.AsyncInterceptor.Tests/CustomTaskLikeReturnValueExample/AsyncTaskBuilderOfMyTask`.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using Castle.DynamicProxy; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Runtime.CompilerServices; | ||
using System.Threading.Tasks; | ||
|
||
namespace Kunet.AsyncInterceptor; | ||
|
||
public partial class AsyncAdapter | ||
{ | ||
internal static readonly Dictionary<Type, Func<IInvocation, AsyncAdapter>> FactoryCache = new(); // Task -> (invocation => new AsyncAdapterOfTask(invocation)) | ||
internal static readonly Dictionary<Type, Type> OpenGenericTypesRegistration = new(); // Task<T> -> AsyncAdapterOfTask<T> | ||
|
||
static AsyncAdapter() | ||
{ | ||
Register<Task>(x => new AsyncAdapterOfTask(x)); // Task | ||
Register<ValueTask>(x => new AsyncAdapterOfValueTask(x)); // ValueTask | ||
Register(typeof(Task<>), typeof(AsyncAdapterOfTask<>)); // Task<T> | ||
Register(typeof(ValueTask<>), typeof(AsyncAdapterOfValueTask<>)); // ValueTask<T> | ||
} | ||
|
||
public static void Register<T>(Func<IInvocation, AsyncAdapter> factory) => FactoryCache[typeof(T)] = factory; | ||
|
||
public static void Register(Type openGenericReturnType, Type openGenericAsyncAdapterType) => OpenGenericTypesRegistration[openGenericReturnType] = openGenericAsyncAdapterType; | ||
|
||
internal static bool TryCreate(IInvocation invocation, out AsyncAdapter adapter) | ||
{ | ||
var returnType = invocation.Method.ReturnType; | ||
if (FactoryCache.TryGetValue(returnType, out var factory)) | ||
{ | ||
adapter = factory.Invoke(invocation); | ||
return true; | ||
} | ||
if (returnType.IsGenericType && returnType.GenericTypeArguments.Length == 1) | ||
{ | ||
var openGenericReturnType = returnType.GetGenericTypeDefinition(); | ||
if (OpenGenericTypesRegistration.TryGetValue(openGenericReturnType, out var openGenericAsyncAdapterType)) | ||
{ | ||
factory = CreateFactory(openGenericAsyncAdapterType, returnType.GenericTypeArguments); | ||
FactoryCache[returnType] = factory; | ||
adapter = factory.Invoke(invocation); | ||
return true; | ||
} | ||
} | ||
var builderType = | ||
(Attribute.GetCustomAttribute(invocation.Method, typeof(AsyncMethodBuilderAttribute), false) as AsyncMethodBuilderAttribute)?.BuilderType ?? | ||
(Attribute.GetCustomAttribute(invocation.Method.ReturnType, typeof(AsyncMethodBuilderAttribute), false) as AsyncMethodBuilderAttribute)?.BuilderType; | ||
if (builderType is not null) | ||
{ | ||
if (builderType.IsGenericType is false) | ||
{ | ||
adapter = new AsyncAdapterFallback(builderType, invocation); | ||
return true; | ||
} | ||
if (builderType.IsGenericType && returnType.IsGenericType && returnType.GenericTypeArguments.Length == 1) | ||
{ | ||
builderType = builderType.MakeGenericType(returnType.GenericTypeArguments); | ||
adapter = new AsyncAdapterFallback(builderType, invocation); | ||
return true; | ||
} | ||
} | ||
adapter = null; | ||
return false; | ||
} | ||
|
||
private static Func<IInvocation, AsyncAdapter> CreateFactory(Type openGenericReturnType, Type[] typeArguments) | ||
{ | ||
var adapterType = openGenericReturnType.MakeGenericType(typeArguments); | ||
var adapterCtor = adapterType.GetConstructors().Single(); | ||
var parameter = Expression.Parameter(typeof(IInvocation)); | ||
var newInvocation = Expression.New(adapterCtor, parameter); | ||
|
||
return (Func<IInvocation, AsyncAdapter>)Expression.Lambda(newInvocation, parameter).Compile(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using Castle.DynamicProxy; | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
using System.Threading.Tasks; | ||
|
||
namespace Kunet.AsyncInterceptor; | ||
|
||
public abstract partial class AsyncAdapter : IAsyncAdapter | ||
{ | ||
#region IAsyncInvocation | ||
|
||
private readonly IInvocationProceedInfo _proceed; | ||
|
||
protected AsyncAdapter(IInvocation invocation) | ||
{ | ||
Invocation = invocation; | ||
_proceed = invocation.CaptureProceedInfo(); | ||
} | ||
|
||
public IInvocation Invocation { get; } | ||
|
||
public object AsyncResult { get; set; } | ||
|
||
public async ValueTask ProceedAsync() | ||
{ | ||
_proceed.Invoke(); // Invocation.ReturnValue = NEXT() | ||
if (Invocation.ReturnValue is not null) | ||
{ | ||
await SetAsyncResult().ConfigureAwait(false); // AsyncResult = await Invocation.ReturnValue | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// <c>AsyncResult = <see langword="await"/> Invocation.ReturnValue</c> | ||
/// </summary> | ||
protected abstract ValueTask SetAsyncResult(); | ||
|
||
#endregion IAsyncInvocation | ||
|
||
public abstract object Task { get; } | ||
|
||
public abstract void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine; | ||
|
||
public abstract void SetResult(object result); | ||
|
||
public abstract void SetException(Exception exception); | ||
|
||
public abstract void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) | ||
where TAwaiter : ICriticalNotifyCompletion | ||
where TStateMachine : IAsyncStateMachine; | ||
} |
Oops, something went wrong.