-
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
7 changed files
with
165 additions
and
39 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
40 changes: 32 additions & 8 deletions
40
Kunet.AsyncInterceptor/AsyncAdapters/AsyncAdapterOfTask.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 |
---|---|---|
@@ -1,25 +1,49 @@ | ||
using Castle.DynamicProxy; | ||
using System; | ||
using System.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using System.Threading.Tasks; | ||
|
||
namespace Kunet.AsyncInterceptor; | ||
|
||
internal sealed class AsyncAdapterOfTask : AsyncAdapter | ||
[StructLayout(LayoutKind.Auto)] | ||
internal struct AsyncAdapterOfTask : IAsyncInvocation, IAsyncAdapter | ||
{ | ||
private readonly IInvocationProceedInfo _proceed; | ||
private readonly AsyncTaskMethodBuilder _builder = AsyncTaskMethodBuilder.Create(); | ||
|
||
public AsyncAdapterOfTask(IInvocation invocation) : base(invocation) => Task = _builder.Task; | ||
public AsyncAdapterOfTask(IInvocation invocation) | ||
{ | ||
_proceed = invocation.CaptureProceedInfo(); | ||
Invocation = invocation; | ||
Task = _builder.Task; | ||
} | ||
|
||
protected override ValueTask SetAsyncResult() => new((Task)Invocation.ReturnValue); | ||
public IInvocation Invocation { get; } | ||
|
||
public override object Task { get; } | ||
public object AsyncResult { get; set; } | ||
|
||
public override void Start<TStateMachine>(ref TStateMachine stateMachine) => _builder.Start(ref stateMachine); | ||
public object Task { get; } | ||
|
||
public override void SetResult(object result) => _builder.SetResult(); | ||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) | ||
where TAwaiter : ICriticalNotifyCompletion | ||
where TStateMachine : IAsyncStateMachine => _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | ||
|
||
public override void SetException(Exception exception) => _builder.SetException(exception); | ||
public ValueTask ProceedAsync() | ||
{ | ||
_proceed.Invoke(); // Invocation.ReturnValue = NEXT() | ||
if (Invocation.ReturnValue is not null) | ||
{ | ||
Debug.Assert(Invocation.ReturnValue is Task); | ||
return new((Task)Invocation.ReturnValue); // AsyncResult = await Invocation.ReturnValue | ||
} | ||
return default; | ||
} | ||
|
||
public override void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) => _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | ||
public void SetException(Exception exception) => _builder.SetException(exception); | ||
|
||
public void SetResult(object result) => _builder.SetResult(); | ||
|
||
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => _builder.Start(ref stateMachine); | ||
} |
40 changes: 32 additions & 8 deletions
40
Kunet.AsyncInterceptor/AsyncAdapters/AsyncAdapterOfValueTask.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 |
---|---|---|
@@ -1,25 +1,49 @@ | ||
using Castle.DynamicProxy; | ||
using System; | ||
using System.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using System.Threading.Tasks; | ||
|
||
namespace Kunet.AsyncInterceptor; | ||
|
||
internal sealed class AsyncAdapterOfValueTask : AsyncAdapter | ||
[StructLayout(LayoutKind.Auto)] | ||
internal struct AsyncAdapterOfValueTask : IAsyncInvocation, IAsyncAdapter | ||
{ | ||
private readonly IInvocationProceedInfo _proceed; | ||
private readonly AsyncValueTaskMethodBuilder _builder = AsyncValueTaskMethodBuilder.Create(); | ||
|
||
public AsyncAdapterOfValueTask(IInvocation invocation) : base(invocation) => Task = _builder.Task; | ||
public AsyncAdapterOfValueTask(IInvocation invocation) | ||
{ | ||
_proceed = invocation.CaptureProceedInfo(); | ||
Invocation = invocation; | ||
Task = _builder.Task; | ||
} | ||
|
||
protected override ValueTask SetAsyncResult() => (ValueTask)Invocation.ReturnValue; | ||
public IInvocation Invocation { get; } | ||
|
||
public override object Task { get; } | ||
public object AsyncResult { get; set; } | ||
|
||
public override void Start<TStateMachine>(ref TStateMachine stateMachine) => _builder.Start(ref stateMachine); | ||
public object Task { get; } | ||
|
||
public override void SetResult(object result) => _builder.SetResult(); | ||
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) | ||
where TAwaiter : ICriticalNotifyCompletion | ||
where TStateMachine : IAsyncStateMachine => _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | ||
|
||
public override void SetException(Exception exception) => _builder.SetException(exception); | ||
public ValueTask ProceedAsync() | ||
{ | ||
_proceed.Invoke(); // Invocation.ReturnValue = NEXT() | ||
if (Invocation.ReturnValue is not null) | ||
{ | ||
Debug.Assert(Invocation.ReturnValue is ValueTask); | ||
return (ValueTask)Invocation.ReturnValue; // AsyncResult = await Invocation.ReturnValue | ||
} | ||
return default; | ||
} | ||
|
||
public override void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) => _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | ||
public void SetException(Exception exception) => _builder.SetException(exception); | ||
|
||
public void SetResult(object result) => _builder.SetResult(); | ||
|
||
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => _builder.Start(ref stateMachine); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Kunet.AsyncInterceptor; | ||
|
||
[StructLayout(LayoutKind.Auto)] | ||
internal struct AsyncStateMachine<T> : IAsyncStateMachine where T : IAsyncAdapter | ||
{ | ||
private readonly T _adapter; | ||
private readonly AsyncInterceptor _interceptor; | ||
private bool _intercepting; | ||
private ValueTaskAwaiter _interceptingAwaiter; | ||
|
||
public AsyncStateMachine(in T adapter, AsyncInterceptor interceptor) | ||
{ | ||
_adapter = adapter; | ||
_interceptor = interceptor; | ||
} | ||
|
||
public void MoveNext() | ||
{ | ||
try | ||
{ | ||
if (_intercepting is false) | ||
{ | ||
_intercepting = true; | ||
_interceptingAwaiter = _interceptor.InternalInterceptAsync(_adapter).GetAwaiter(); | ||
} | ||
if (_interceptingAwaiter.IsCompleted) | ||
{ | ||
_interceptingAwaiter.GetResult(); // throw exception if there is. | ||
_adapter.SetResult(_adapter.AsyncResult); | ||
} | ||
else | ||
{ | ||
_adapter.AwaitUnsafeOnCompleted(ref _interceptingAwaiter, ref this); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_adapter.SetException(ex); | ||
} | ||
} | ||
|
||
[Obsolete] | ||
public void SetStateMachine(IAsyncStateMachine stateMachine) | ||
{ | ||
// SetStateMachine was originally needed in order to store the boxed state machine reference into the boxed copy. | ||
// Now that a normal box is no longer used, SetStateMachine is also legacy. We need not do anything here. | ||
// https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs,70528b49b7e9916f | ||
} | ||
} |